From 955f98cfe99eb985d2b7d6b99f11ceb8bc8ec86f Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Wed, 18 Mar 2026 04:58:22 +0000 Subject: [PATCH 01/17] chore(release): Bumped to Version 16.10.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # [16.10.0](https://github.com/frappe/erpnext/compare/v16.9.1...v16.10.0) (2026-03-18) ### Bug Fixes * add icon in clear demo data ([0c9ce93](https://github.com/frappe/erpnext/commit/0c9ce9306f6d473515ffbef6d8519fcce3b47564)) * add item_name to quick entry fields in Item doctype (backport [#53530](https://github.com/frappe/erpnext/issues/53530)) ([#53533](https://github.com/frappe/erpnext/issues/53533)) ([a695a11](https://github.com/frappe/erpnext/commit/a695a111306ff3d97584522162e460912965b3eb)) * add validation in bom creator function (backport [#53364](https://github.com/frappe/erpnext/issues/53364)) ([#53368](https://github.com/frappe/erpnext/issues/53368)) ([4af54a7](https://github.com/frappe/erpnext/commit/4af54a7ac7a1c630bcb5016893fc438f604e8679)) * Append existing ignored doctypes in Journal Entry on_cancel instead of overwriting ([875114d](https://github.com/frappe/erpnext/commit/875114d33ccd270f9477141b38b6292c95976929)) * **banking:** include paid purchase invoices in reports and bank clearance ([#52675](https://github.com/frappe/erpnext/issues/52675)) ([c9efcb7](https://github.com/frappe/erpnext/commit/c9efcb782206799a55ed61e92b24a1412daacb71)) * broke cost center filter in get outstanding reference docs ([60a9c08](https://github.com/frappe/erpnext/commit/60a9c08f0dccc30675ee8795eff97c6279215728)) * change "Date" label to "Posting Date" in Sales Invoice and Purchase Invoice (backport [#53503](https://github.com/frappe/erpnext/issues/53503)) ([#53517](https://github.com/frappe/erpnext/issues/53517)) ([e72f398](https://github.com/frappe/erpnext/commit/e72f398b7ca2ec677fbace115fcdd5f65bd4239c)) * correct overlap detection in JobCard.has_overlap (backport [#53473](https://github.com/frappe/erpnext/issues/53473)) ([#53523](https://github.com/frappe/erpnext/issues/53523)) ([c8bb55f](https://github.com/frappe/erpnext/commit/c8bb55f35bf528acb43eca7b4600edd299c94d05)) * correctly group RMs of same phantom from different FG ([efce145](https://github.com/frappe/erpnext/commit/efce145dad454644c2484d13fb355a4c0059f589)) * Creating new item price incase of changes in expired item price (backport [#53534](https://github.com/frappe/erpnext/issues/53534)) ([#53545](https://github.com/frappe/erpnext/issues/53545)) ([e2a34ab](https://github.com/frappe/erpnext/commit/e2a34ab3fe824ff96dabddcffb45bbcb1103f72e)) * **delivery note:** avoid maintaining si_detail on return delivery note (backport [#52456](https://github.com/frappe/erpnext/issues/52456)) ([#53353](https://github.com/frappe/erpnext/issues/53353)) ([82b97ab](https://github.com/frappe/erpnext/commit/82b97abbad63b9e3668009c0c3ee5992ac71ab53)) * do not modify rate in the child item merely for comparison (backport [#53301](https://github.com/frappe/erpnext/issues/53301)) ([#53376](https://github.com/frappe/erpnext/issues/53376)) ([42cfbae](https://github.com/frappe/erpnext/commit/42cfbae782d62d916a9efb5842e14edb42051309)) * do not set valuation rate for invoice without update stock ([7af4aca](https://github.com/frappe/erpnext/commit/7af4acab297182be5eeeaaee1fe330d4c20b991a)) * enable logs to track changes in doctype. (backport [#53491](https://github.com/frappe/erpnext/issues/53491)) ([#53524](https://github.com/frappe/erpnext/issues/53524)) ([afe8e3a](https://github.com/frappe/erpnext/commit/afe8e3a023cda96af8a6bdedcf8a437cd41e1875)) * handle NoneType error while creating a item (backport [#53313](https://github.com/frappe/erpnext/issues/53313)) ([#53351](https://github.com/frappe/erpnext/issues/53351)) ([4a7fdd1](https://github.com/frappe/erpnext/commit/4a7fdd1f91fe9a91c8ab93d5e3621a360c501024)) * 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)) ([#53582](https://github.com/frappe/erpnext/issues/53582)) ([573a402](https://github.com/frappe/erpnext/commit/573a402ee54c1c5d26ab15a4e614ffcb3e37574a)) * **italy:** fix e-invoice ScontoMaggiorazione structure and included_in_print_rate support (backport [#53334](https://github.com/frappe/erpnext/issues/53334)) ([#53569](https://github.com/frappe/erpnext/issues/53569)) ([535543d](https://github.com/frappe/erpnext/commit/535543d406f0309c69b799be7fedf6bc0709f792)) * **manufacturing:** update working hours validation (backport [#53559](https://github.com/frappe/erpnext/issues/53559)) ([#53567](https://github.com/frappe/erpnext/issues/53567)) ([49ac166](https://github.com/frappe/erpnext/commit/49ac166f9e819861c37a3bfc747c3b50d2f5d68f)) * move show_general_ledger to Asset Repair form events ([0a5fe99](https://github.com/frappe/erpnext/commit/0a5fe99d4a33b181fea42cd57aae4f101918bc82)) * NoneType error when template description is to be copied to variant (backport [#53358](https://github.com/frappe/erpnext/issues/53358)) ([#53366](https://github.com/frappe/erpnext/issues/53366)) ([24910cf](https://github.com/frappe/erpnext/commit/24910cf2d20a7be3b6c50cf5a1a1534d1dcabc85)) * **p&l_statement:** disable accumulated value filter by default (backport [#53488](https://github.com/frappe/erpnext/issues/53488)) ([#53490](https://github.com/frappe/erpnext/issues/53490)) ([1ecc04c](https://github.com/frappe/erpnext/commit/1ecc04c7a2583ef3e5977c74ab980506a024796e)) * precision issue in production plan (backport [#53370](https://github.com/frappe/erpnext/issues/53370)) ([#53374](https://github.com/frappe/erpnext/issues/53374)) ([6660e64](https://github.com/frappe/erpnext/commit/6660e643bbd4f3677df09a905d1741c1560d982e)) * re-calculate taxes and totals after resetting bundle item rate (backport [#53342](https://github.com/frappe/erpnext/issues/53342)) ([#53350](https://github.com/frappe/erpnext/issues/53350)) ([541bfb6](https://github.com/frappe/erpnext/commit/541bfb664bc70c4d52d722c0f7c06c69687b8b6f)) * **regional:** rename duplicate Customer fields in Italy setup (backport [#50921](https://github.com/frappe/erpnext/issues/50921)) ([#53398](https://github.com/frappe/erpnext/issues/53398)) ([41bcf96](https://github.com/frappe/erpnext/commit/41bcf96601c7a2a7dc992e8832f21cd9eeb3a40a)) * remove payables and receivables workspace ([c48a886](https://github.com/frappe/erpnext/commit/c48a8868c281d6e8d35ae5c3d112ca101cb8f0c0)) * remove redundant pos print format ([#53348](https://github.com/frappe/erpnext/issues/53348)) ([270a294](https://github.com/frappe/erpnext/commit/270a294e81a00b294270bf05864b7741b9c33fa0)) * remove supplier selection dialog when creating Purchase Order from Material Request (backport [#53391](https://github.com/frappe/erpnext/issues/53391)) ([#53476](https://github.com/frappe/erpnext/issues/53476)) ([3603048](https://github.com/frappe/erpnext/commit/36030483e5d2723e8ea406389171dd1a92863c13)) * remove workspace sidebar for payables and receivables ([4e5703c](https://github.com/frappe/erpnext/commit/4e5703c22344ddf545dcef00ef22f3f129552d01)) * sales order indicator should be based on available qty rather th… (backport [#53456](https://github.com/frappe/erpnext/issues/53456)) ([#53458](https://github.com/frappe/erpnext/issues/53458)) ([ab8fe14](https://github.com/frappe/erpnext/commit/ab8fe146abd20532275c2e6a236421410a9f8f17)) * **sales_invoice:** reset payment methods on `pos_profile` change (backport [#53514](https://github.com/frappe/erpnext/issues/53514)) ([#53561](https://github.com/frappe/erpnext/issues/53561)) ([4d197b1](https://github.com/frappe/erpnext/commit/4d197b1b7cad526c353a911b36976e0124c6282d)) * **serial_and_batch_bundle_selector:** handle CSV attachment properly (backport [#53460](https://github.com/frappe/erpnext/issues/53460)) ([#53462](https://github.com/frappe/erpnext/issues/53462)) ([3b2ae7b](https://github.com/frappe/erpnext/commit/3b2ae7ba4f0d34da35d9a502ae020746ac691a31)) * stock adjustment entry ([cecdcff](https://github.com/frappe/erpnext/commit/cecdcffce8f564fa14a40fbe339658d0b31dd5c3)) * **stock:** fix the property setter (backport [#53422](https://github.com/frappe/erpnext/issues/53422)) ([#53574](https://github.com/frappe/erpnext/issues/53574)) ([9ccafd3](https://github.com/frappe/erpnext/commit/9ccafd30be279f2a0d843a4767a969312ec88bb9)) * **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)) ([#53505](https://github.com/frappe/erpnext/issues/53505)) ([b7400b9](https://github.com/frappe/erpnext/commit/b7400b9b3594b115276141eada8522cbdfdef419)) * update child item schedule_date and prevent past dates (backport [#53298](https://github.com/frappe/erpnext/issues/53298)) ([#53346](https://github.com/frappe/erpnext/issues/53346)) ([a4d2c34](https://github.com/frappe/erpnext/commit/a4d2c34ddebdd6a425f6882d3cd2356351b46e62)) * update item description in Production Plan Assembly Items table ([d43c04d](https://github.com/frappe/erpnext/commit/d43c04df8810179db20e0f2d44b88f14acd3e0ea)) * update label on company change ([bb98acb](https://github.com/frappe/erpnext/commit/bb98acb0c07a38d2e13dcd743574fe02d74a067a)) * use bom source warehouse in WO created from PP (backport [#53478](https://github.com/frappe/erpnext/issues/53478)) ([#53480](https://github.com/frappe/erpnext/issues/53480)) ([31ab757](https://github.com/frappe/erpnext/commit/31ab75787e0050938d492fa5e816c3cc3747b8c4)) * use correct filter to get the composite assets ([82eb200](https://github.com/frappe/erpnext/commit/82eb200c738f42ff358fd21a97bfc0f43ee6331e)) * use qb to prevent incorrect sql due to user permissions ([236f1bb](https://github.com/frappe/erpnext/commit/236f1bbfdb6e392b7209219dd71db9a147581ac7)) * use same label ([10cb6f8](https://github.com/frappe/erpnext/commit/10cb6f83060f043a3cb17490d70fad9f4e9f1298)) * valuation rate for no Use Batch wise Valuation batches ([8f31b0d](https://github.com/frappe/erpnext/commit/8f31b0dccd6e0fb2abfab6cac0fef2e5e4da2c79)) ### Features * Adding requested qty in packed item (backport [#53486](https://github.com/frappe/erpnext/issues/53486)) ([#53521](https://github.com/frappe/erpnext/issues/53521)) ([8753ed9](https://github.com/frappe/erpnext/commit/8753ed9992a6deac6d3897f69bfe256ea4606217)) * show subsidiary companies value in purchase analytics ([c8afc04](https://github.com/frappe/erpnext/commit/c8afc04957e2eed5be11389dfa5de3c75ed2d0b8)) * **stock:** implement fallback logic for Delivery Trip address mapping (backport [#53260](https://github.com/frappe/erpnext/issues/53260)) ([#53444](https://github.com/frappe/erpnext/issues/53444)) ([6ca5f35](https://github.com/frappe/erpnext/commit/6ca5f355bf8d493541729f7a1b573170fd9a54b1)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index b1f745b986b..2ed93c3757d 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.9.1" +__version__ = "16.10.0" def get_default_company(user=None): From 9a46aa310662949d73f1d1f77b0fd896a728b52f Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Wed, 18 Mar 2026 18:49:30 +0530 Subject: [PATCH 02/17] fix: incorrect sle calculation when doc has project (#53599) (cherry picked from commit 6cb6a52ded9addd3e0e54b0b59ebd6d34d357b4a) (cherry picked from commit 55bad49cf0a1583b58b66670c579543476915532) --- 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 225d9010592..e2bcc3dc6f3 100644 --- a/erpnext/stock/report/stock_ledger/stock_ledger.py +++ b/erpnext/stock/report/stock_ledger/stock_ledger.py @@ -689,6 +689,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 dadc586edb4..ae643406982 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -1781,7 +1781,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 @@ -1797,7 +1797,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 {} @@ -1811,6 +1811,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" @@ -1865,7 +1866,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 8b10311a9bd10f376f3b962938b8f22e6a6d2186 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Wed, 18 Mar 2026 13:42:27 +0000 Subject: [PATCH 03/17] chore(release): Bumped to Version 16.10.1 ## [16.10.1](https://github.com/frappe/erpnext/compare/v16.10.0...v16.10.1) (2026-03-18) ### Bug Fixes * incorrect sle calculation when doc has project ([#53599](https://github.com/frappe/erpnext/issues/53599)) ([9a46aa3](https://github.com/frappe/erpnext/commit/9a46aa310662949d73f1d1f77b0fd896a728b52f)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 2ed93c3757d..b520440dc54 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.10.0" +__version__ = "16.10.1" def get_default_company(user=None): From 372fc96f0cfa470bfd455953b5eed2e64a534ac8 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Mon, 23 Mar 2026 16:35:10 +0000 Subject: [PATCH 04/17] chore(release): Bumped to Version 16.11.0 # [16.11.0](https://github.com/frappe/erpnext/compare/v16.10.1...v16.11.0) (2026-03-23) ### Bug Fixes * Adding validation for operation time in BOM ([c38b252](https://github.com/frappe/erpnext/commit/c38b252289b46d6cc48667fe4b5fced7bbe3dd55)) * batch validation for subcontracting receipt ([604739d](https://github.com/frappe/erpnext/commit/604739d1dca4a9c5bd0117c33c47a40d04d97fa4)) * check for `submit` permissions instead of `write` permissions when updating status (backport [#53697](https://github.com/frappe/erpnext/issues/53697)) ([#53703](https://github.com/frappe/erpnext/issues/53703)) ([cd1dfee](https://github.com/frappe/erpnext/commit/cd1dfeeab300f81bfba5461cf1c4bfaa81472fae)) * check posting_date in args (backport [#53303](https://github.com/frappe/erpnext/issues/53303)) ([#53612](https://github.com/frappe/erpnext/issues/53612)) ([f394ead](https://github.com/frappe/erpnext/commit/f394ead878642ef8feea7d91fb500d3285b17845)) * consider returned qty in subcontracting report (backport [#53616](https://github.com/frappe/erpnext/issues/53616)) ([#53621](https://github.com/frappe/erpnext/issues/53621)) ([7edcef1](https://github.com/frappe/erpnext/commit/7edcef124876938894f8abf63e100fffe7413638)) * deadlock issue for SLE ([de41aba](https://github.com/frappe/erpnext/commit/de41abaaf29962df3614fb91d77a657430958a44)) * do not overwrite expense account in stock entry (backport [#53658](https://github.com/frappe/erpnext/issues/53658)) ([#53661](https://github.com/frappe/erpnext/issues/53661)) ([077f397](https://github.com/frappe/erpnext/commit/077f39721a9e56d2b011519506350b7f755ac512)) * do not update float precision on setup ([0af4cd9](https://github.com/frappe/erpnext/commit/0af4cd9098ef3d871ff426fb400cfdb605f610bb)) * ignore cost center (backport [#53063](https://github.com/frappe/erpnext/issues/53063)) ([#53614](https://github.com/frappe/erpnext/issues/53614)) ([2ccac6c](https://github.com/frappe/erpnext/commit/2ccac6c47982a79975bc63cec59df89db2d260de)) * incorrect sle calculation when doc has project ([#53599](https://github.com/frappe/erpnext/issues/53599)) ([55bad49](https://github.com/frappe/erpnext/commit/55bad49cf0a1583b58b66670c579543476915532)) * **manufacturing:** update non-stock item dict (backport [#53689](https://github.com/frappe/erpnext/issues/53689)) ([#53699](https://github.com/frappe/erpnext/issues/53699)) ([0d9af60](https://github.com/frappe/erpnext/commit/0d9af60f8aa52f6c244adb16a04e6580ab6f1be9)) * merge conflict ([f1c93d4](https://github.com/frappe/erpnext/commit/f1c93d4b98181828e2825b2ef82d733e4f99ad25)) * **payment_schedule:** using `show_alert` instead of `msgprint` for non-selection of payment schedule (backport [#53623](https://github.com/frappe/erpnext/issues/53623)) ([#53631](https://github.com/frappe/erpnext/issues/53631)) ([a94bf6d](https://github.com/frappe/erpnext/commit/a94bf6db060a55680a590c5e72870579f8eacc35)) * PO should not be required for internal transfers (backport [#53681](https://github.com/frappe/erpnext/issues/53681)) ([#53684](https://github.com/frappe/erpnext/issues/53684)) ([5f9533f](https://github.com/frappe/erpnext/commit/5f9533f0899c1194db910f85696b978dc7e7bc22)) * python error in manufacture entry if transfer against is job card (backport [#53615](https://github.com/frappe/erpnext/issues/53615)) ([#53618](https://github.com/frappe/erpnext/issues/53618)) ([10a40a6](https://github.com/frappe/erpnext/commit/10a40a6d9b044f1b7d97d391785f54f5ecbf6a03)) * set customer details on customer creation at login (backport [#53509](https://github.com/frappe/erpnext/issues/53509)) ([#53629](https://github.com/frappe/erpnext/issues/53629)) ([5b4e3e9](https://github.com/frappe/erpnext/commit/5b4e3e92df097da7567a201f97cf766035a67036)) * shipping rule applied twice on non stock items (backport [#53655](https://github.com/frappe/erpnext/issues/53655)) ([#53687](https://github.com/frappe/erpnext/issues/53687)) ([9805745](https://github.com/frappe/erpnext/commit/9805745a66cb2a27d465de466cd9d62fc2b82082)) * stock queue for SABB ([f570a4c](https://github.com/frappe/erpnext/commit/f570a4cb5d78503d2bbdf0fd808a5045657a1ae2)) * **stock:** add company filter while fetching batches (backport [#53369](https://github.com/frappe/erpnext/issues/53369)) ([#53581](https://github.com/frappe/erpnext/issues/53581)) ([91ee45a](https://github.com/frappe/erpnext/commit/91ee45a698c1dd8332808d63df7005681663df77)) * **stock:** fix email error message (backport [#53606](https://github.com/frappe/erpnext/issues/53606)) ([#53633](https://github.com/frappe/erpnext/issues/53633)) ([48e8944](https://github.com/frappe/erpnext/commit/48e8944a867f39f459ff2324407df3530bb56efa)) * **stock:** handle NoneType error (backport [#53593](https://github.com/frappe/erpnext/issues/53593)) ([#53627](https://github.com/frappe/erpnext/issues/53627)) ([2d1dd03](https://github.com/frappe/erpnext/commit/2d1dd034838d2223ac6f09d44fd6cf5b8586a54f)) * test case ([aac60b4](https://github.com/frappe/erpnext/commit/aac60b4c134b01224b606d19a85ef81602fc2b79)) * **test:** Use the system-configured float precision ([dd7cc56](https://github.com/frappe/erpnext/commit/dd7cc56dfe4ff316d87352719ce269481f44e049)) * **trends:** added validation for `period_based_on` filter (backport [#53690](https://github.com/frappe/erpnext/issues/53690)) ([#53692](https://github.com/frappe/erpnext/issues/53692)) ([9787777](https://github.com/frappe/erpnext/commit/9787777cbddeb76b90ae976e5f318724b9d80907)) * use correct test class ([1efbc60](https://github.com/frappe/erpnext/commit/1efbc60df1c934476090cd484299541591578a91)) * validate permission before updating status (backport [#53651](https://github.com/frappe/erpnext/issues/53651)) ([#53653](https://github.com/frappe/erpnext/issues/53653)) ([7ebed91](https://github.com/frappe/erpnext/commit/7ebed912cfaaacef61e1dccf6bd779775dedfcc0)) ### Features * add cost center field to the stock entry accounting dimension tab ([50da693](https://github.com/frappe/erpnext/commit/50da6937e1a4523e3393bce06b104b71e213ee4e)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index b520440dc54..b7b769a1050 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.10.1" +__version__ = "16.11.0" def get_default_company(user=None): From ddef35c333be4a3f93cb6fbf08f79b0e8d30e8b0 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Mon, 30 Mar 2026 18:03:06 +0000 Subject: [PATCH 05/17] chore(release): Bumped to Version 16.12.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # [16.12.0](https://github.com/frappe/erpnext/compare/v16.11.0...v16.12.0) (2026-03-30) ### Bug Fixes * **accounts:** set supplier name as title field in Purchase Invoice ([#53710](https://github.com/frappe/erpnext/issues/53710)) ([f2195fa](https://github.com/frappe/erpnext/commit/f2195fa67d6507e049c0d9edd305c8186fa665ae)) * add missing type hints to whitelisted function arguments ([b115913](https://github.com/frappe/erpnext/commit/b115913fc9ebc23bb55197c4a78cbd567c1e3dc0)) * avoid setting unnecessary fields ([3023302](https://github.com/frappe/erpnext/commit/3023302700d5638c45f3a7158ce56feff73179e6)) * **bank_account:** added validation to fetch bank account details using `get_bank_account_details` (backport [#53926](https://github.com/frappe/erpnext/issues/53926)) ([#53930](https://github.com/frappe/erpnext/issues/53930)) ([8cb8f66](https://github.com/frappe/erpnext/commit/8cb8f66b22af3618f3e769b13665a67537162c4d)) * change in functionality ([6d92792](https://github.com/frappe/erpnext/commit/6d92792634eda965b5269cf161cb5c73d86c9225)) * change shipment parcel dimension fields from Int to Float (backport [#53867](https://github.com/frappe/erpnext/issues/53867)) ([#53873](https://github.com/frappe/erpnext/issues/53873)) ([2907c41](https://github.com/frappe/erpnext/commit/2907c411f344053804f154358650939853f20ffa)) * **contract_template:** restrict `create`, `write` and `delete` access only to `System Manager` (backport [#53787](https://github.com/frappe/erpnext/issues/53787)) ([#53789](https://github.com/frappe/erpnext/issues/53789)) ([737cb37](https://github.com/frappe/erpnext/commit/737cb371d799066ca8f3dd4a8c63866aed6673fb)) * correct item valuation when "Deduct" is used in Purchase Invoice and Receipt. ([c6fe5be](https://github.com/frappe/erpnext/commit/c6fe5be95a5f5b4bc4a8334ae5f017ea82999d36)) * corrected logic to retry reposting if timeout occurs after dependent SLE processing ([8fbb86d](https://github.com/frappe/erpnext/commit/8fbb86d53e6bea3ea10b582252c4babbaae978ed)) * do not check for sub assembly reference for rm of fg (backport [#53758](https://github.com/frappe/erpnext/issues/53758)) ([#53759](https://github.com/frappe/erpnext/issues/53759)) ([1872dcc](https://github.com/frappe/erpnext/commit/1872dccb0a59ba2b0d68d3a67a05a6fa95ff5239)) * **email_campaign:** prevent unsubscribing entire campaign when email group member unsubscribes ([00bb07a](https://github.com/frappe/erpnext/commit/00bb07aaa3ee6c6b1d28679d6a4234e692bad289)) * employee user creation ([1ddadb7](https://github.com/frappe/erpnext/commit/1ddadb72b7a2762bb179fdf141065485b08d6001)) * **employee:** add 'set_only_once' property to 'Create User Automatically' field ([eadf78d](https://github.com/frappe/erpnext/commit/eadf78d69424e2fb64d0ef7c944e79d1ad9b6b64)) * fallback to Personal Email for user creation just like client-side ([553bc87](https://github.com/frappe/erpnext/commit/553bc87ac7665dad83ec56eaafa6888da441e63f)) * flaky currency exchange test (backport [#53813](https://github.com/frappe/erpnext/issues/53813)) ([#53817](https://github.com/frappe/erpnext/issues/53817)) ([3d79dce](https://github.com/frappe/erpnext/commit/3d79dce8b3f9b027639c5b49cb040f8bfdfa08d1)) * hide Create User Automatically checkbox if user is already selected ([c12ad79](https://github.com/frappe/erpnext/commit/c12ad7910a62481f8df91a95c4353fa48f5000c8)) * invalid dynamic link filter for address doctype (backport [#53849](https://github.com/frappe/erpnext/issues/53849)) ([#53852](https://github.com/frappe/erpnext/issues/53852)) ([1c1369f](https://github.com/frappe/erpnext/commit/1c1369fea8a20e7a62fc13bea669ad40dd481ec8)) * **item_dashboard:** escaping `warehouse`, `item_code`, `stock_uom` and `item_name` on `get_data` (backport [#53904](https://github.com/frappe/erpnext/issues/53904)) ([#53914](https://github.com/frappe/erpnext/issues/53914)) ([4ac6347](https://github.com/frappe/erpnext/commit/4ac6347cc56fc556fd83e3789d1a3cecb30300ad)) * item-wh reposting, code cleanup ([8d2c4da](https://github.com/frappe/erpnext/commit/8d2c4da9312c5b326e5818557a1262dff64e4bff)) * keep from and to time blank until added explicitly (backport [#53798](https://github.com/frappe/erpnext/issues/53798)) ([#53801](https://github.com/frappe/erpnext/issues/53801)) ([09a4f63](https://github.com/frappe/erpnext/commit/09a4f630e13ab8755517a3f0bf4fa2d18319fed6)) * maintain state during reposting ([544c914](https://github.com/frappe/erpnext/commit/544c91441ba2c9ba6eaed19b2b4246c7712b8503)) * **manufacturing:** apply work order status filter in job card (backport [#53766](https://github.com/frappe/erpnext/issues/53766)) ([#53768](https://github.com/frappe/erpnext/issues/53768)) ([37b68a0](https://github.com/frappe/erpnext/commit/37b68a07aa22385cecde0b7f2d296d19b573fac3)) * **manufacturing:** close work order status when stock reservation is… (backport [#53714](https://github.com/frappe/erpnext/issues/53714)) ([#53721](https://github.com/frappe/erpnext/issues/53721)) ([c36f9e9](https://github.com/frappe/erpnext/commit/c36f9e9b1b72295fde10ebd551695e1e3e040e84)) * **manufacturing:** update condition for base hour rate calculation (backport [#53753](https://github.com/frappe/erpnext/issues/53753)) ([#53771](https://github.com/frappe/erpnext/issues/53771)) ([a93d715](https://github.com/frappe/erpnext/commit/a93d7159162f3e3a691ac344bbd402973c28ee02)) * **manufacturing:** update the qty precision (backport [#53874](https://github.com/frappe/erpnext/issues/53874)) ([#53885](https://github.com/frappe/erpnext/issues/53885)) ([f6fa972](https://github.com/frappe/erpnext/commit/f6fa9726f9a5d068e5ce0afdd46cd9519445d45f)) * move Joining section before Exit, relabel Employee Exit -> Exit ([7414a9a](https://github.com/frappe/erpnext/commit/7414a9a69450112c0ff5d65bba1c1ad083a99009)) * only validate auto user creation before insert ([2f13b33](https://github.com/frappe/erpnext/commit/2f13b33e3da4a27645a0e8bc5f0cb67dc3b07020)) * **opening_invoice_creation_tool:** sanitize summary content for dashboard (backport [#53917](https://github.com/frappe/erpnext/issues/53917)) ([#53924](https://github.com/frappe/erpnext/issues/53924)) ([8c35a93](https://github.com/frappe/erpnext/commit/8c35a939cb5e9a715402dc0ad4d697c0efeba320)) * party name not updating correctly ([a205733](https://github.com/frappe/erpnext/commit/a2057331e309da6605f625b5c09f0eb4503011bc)) * **Payment Entry:** split orders as per the schedules in the refrence table ([2693ffe](https://github.com/frappe/erpnext/commit/2693ffe6801ad6bfb5ae510a99c2795c3fb86e3a)) * pick correct dependant sle during reposting ([15739b5](https://github.com/frappe/erpnext/commit/15739b5d81fa25fc0aa687af5f32fa4705a1c9d0)) * purchase invoice for internal transfers should not require PO (backport [#53791](https://github.com/frappe/erpnext/issues/53791)) ([#53793](https://github.com/frappe/erpnext/issues/53793)) ([72efbc2](https://github.com/frappe/erpnext/commit/72efbc2b4257a2fba6760cc981409641be833160)) * purchase invoice missing item ([bfb5132](https://github.com/frappe/erpnext/commit/bfb51326edef822a169ccf88766ddc9a416a2e72)) * Removed quick access link from selling workspace ([25fa66f](https://github.com/frappe/erpnext/commit/25fa66f90c7204c5e7e9cf3a953d503afce4a4e7)) * reset employee listview empty state, add import btn instead ([341bfb0](https://github.com/frappe/erpnext/commit/341bfb0bd963a9ae3704c706888390c3fcc2af64)) * reset User ID and make it read-only if 'Create User Automatically' is set ([af94ed8](https://github.com/frappe/erpnext/commit/af94ed865a8b157258cec5785b7ef84319b1e8e7)) * resolve POS crash and correct is_return typo in TransactionBase ([adc2960](https://github.com/frappe/erpnext/commit/adc2960f5b4444149361d5d3ca69ab985f570582)) * sanitize genericode import inputs and secure XML parser ([d7902d0](https://github.com/frappe/erpnext/commit/d7902d0477c6002b63ef02bf57baffe15b06ce04)) * set create user perm to 1 by default + persist option while saving employee ([e8ca394](https://github.com/frappe/erpnext/commit/e8ca394e8b3d918f405dacfb5ddfa7586940eddb)) * set default print format for when downlod pdf ([a5250f8](https://github.com/frappe/erpnext/commit/a5250f88275399725a29474b4eb91bced2407bca)) * skip overwriting existing asset fields with accounting dimensions ([a35a3e9](https://github.com/frappe/erpnext/commit/a35a3e9627355e86f14490df3796f40c05cc8226)) * **stock:** add warehouse filter to pick work order raw materials (backport [#53748](https://github.com/frappe/erpnext/issues/53748)) ([#53898](https://github.com/frappe/erpnext/issues/53898)) ([ad3c1e5](https://github.com/frappe/erpnext/commit/ad3c1e520e3855eeb4ac116c0541151e3570b39d)) * **stock:** handle legacy single sle recon entries ([dd0613a](https://github.com/frappe/erpnext/commit/dd0613a4a8be5b54b873e976a3eec79b8d947196)) * **stock:** ignore qty validation for pick list (backport [#53871](https://github.com/frappe/erpnext/issues/53871)) ([#53892](https://github.com/frappe/erpnext/issues/53892)) ([319ba31](https://github.com/frappe/erpnext/commit/319ba31b7708fa76365f8dc9616db84330c91048)) * **stock:** update company validation for expense account in lcv ([9d46d81](https://github.com/frappe/erpnext/commit/9d46d8151a92e3d098c546504a62fdc8468d3d93)) * support translated search in get_party_type and refactor raw sql to qb (backport [#53191](https://github.com/frappe/erpnext/issues/53191)) ([#53832](https://github.com/frappe/erpnext/issues/53832)) ([675b94b](https://github.com/frappe/erpnext/commit/675b94b7a20305f00af6670215c176fce2f0a7f3)) * **templates:** escape attachment `file_url` and `file_name` in `order.html` and `projects.html` ([38bc5d6](https://github.com/frappe/erpnext/commit/38bc5d69cdeccbd1030fcac72831e0eb36e92a72)) * **templates:** using correct syntax of `include` in `projects.html` ([c3cb9cc](https://github.com/frappe/erpnext/commit/c3cb9cc003a17c6b88a22687532652647755b8a6)) * test case ([5039f89](https://github.com/frappe/erpnext/commit/5039f896bf93a7c618cb3edbcff3ad9bad452f84)) * test file deletion ([3a8e1e3](https://github.com/frappe/erpnext/commit/3a8e1e3faa57c016decd7a1e4c99d7b7cf4938e7)) * **test:** enable perpetual inventory ([ad96646](https://github.com/frappe/erpnext/commit/ad966468b16e8b009e97880970e8aa4c4b0065d0)) * uncollapse User Details section in new form ([d093b71](https://github.com/frappe/erpnext/commit/d093b719463685ff7150770ef0a806c98e345a25)) * **UX:** improve party selection UX with party name field ([f80b974](https://github.com/frappe/erpnext/commit/f80b974d6faaf29b7b7285ec4319ceec30005740)) * validate if quantity greater than 0 in item dashboard (backport [#53846](https://github.com/frappe/erpnext/issues/53846)) ([#53848](https://github.com/frappe/erpnext/issues/53848)) ([9a2851f](https://github.com/frappe/erpnext/commit/9a2851f221fc708d818e4f42f2836266128c3d85)) * **warehouse_capacity_dashboard:** escaping `warehouse`, `item_code` and `company` on `get_data` (backport [#53894](https://github.com/frappe/erpnext/issues/53894)) ([#53900](https://github.com/frappe/erpnext/issues/53900)) ([f01f7e7](https://github.com/frappe/erpnext/commit/f01f7e7974149f64bd7622d0752cb5673704354b)) ### Features * Bom stock analysis report ([8a5e2cc](https://github.com/frappe/erpnext/commit/8a5e2cc0a678a08fc22663f559401d2ac8808d0e)) * default print format for Request for Quotation ([ab0e215](https://github.com/frappe/erpnext/commit/ab0e215290609fa887d42480931694c6670630f7)) * **employee:** Add automatic user creation feature and related validations. Create User on Import. ([8f8b487](https://github.com/frappe/erpnext/commit/8f8b48746baf0572a39c7a5f2272bd8b75131f50)) * **employee:** Add birthdays and work anniversaries indicator in form ,list view enhancements and new empty state. ([0b3c912](https://github.com/frappe/erpnext/commit/0b3c9120c36aed755e496925f2e05527fe96176f)) * **employee:** Create User button and form. ([cd0a25c](https://github.com/frappe/erpnext/commit/cd0a25ca174d88dac8cc8a9ae637189ceff8ed66)) * **report:** add service start/end date and amount with roll-ups in deferred revenue/expense report ([407c3cd](https://github.com/frappe/erpnext/commit/407c3cd5752bdea8adf006dce86620a1a2a85f14)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index b7b769a1050..92caee79427 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.11.0" +__version__ = "16.12.0" def get_default_company(user=None): From 1134e25bb6ec7ce2a77a29f9bc4e09b0434a4628 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 7 Apr 2026 17:58:52 +0000 Subject: [PATCH 06/17] chore(release): Bumped to Version 16.13.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # [16.13.0](https://github.com/frappe/erpnext/compare/v16.12.0...v16.13.0) (2026-04-07) ### Bug Fixes * add support to fetch items based on manufacture stock entry; fix how it's done from work order ([4232640](https://github.com/frappe/erpnext/commit/4232640a8b2670d04ac585f6a7eb4dc53b32ddf8)) * add tax_id handling in Tax Withholding Entry (backport [#53598](https://github.com/frappe/erpnext/issues/53598)) ([#54081](https://github.com/frappe/erpnext/issues/54081)) ([dc58754](https://github.com/frappe/erpnext/commit/dc58754a60425e455352c148e1c17c8725a6f33e)) * auto-set source_stock_entry ([eead8d6](https://github.com/frappe/erpnext/commit/eead8d6d8c219daa21c5742efe9255fb80833a9e)) * avg stock entries for disassembly from WO ([0ceb084](https://github.com/frappe/erpnext/commit/0ceb08410475c82157dbaff6431dcd06ae1031e2)) * conflicts ([66ee208](https://github.com/frappe/erpnext/commit/66ee208cb2d63dd5052e8a7017dcdd8c968af248)) * correct warehouse preference for disassemble ([919cbd5](https://github.com/frappe/erpnext/commit/919cbd5c0229fdde896afad5dbf58fbe2da65556)) * create source_stock_entry to refer to original manufacturing entry ([b91af5b](https://github.com/frappe/erpnext/commit/b91af5b2b987e04da90c9376261d155b2a665a88)) * custom button to disassemble manufactured stock entry with work order ([84a063a](https://github.com/frappe/erpnext/commit/84a063a9bf5876a5b4f395262318fd6acb9f604f)) * dif_inward_from_outward_workspace_sidebar (backport [#54083](https://github.com/frappe/erpnext/issues/54083)) ([#54088](https://github.com/frappe/erpnext/issues/54088)) ([e6722c8](https://github.com/frappe/erpnext/commit/e6722c84fa4d8ebc2f14af64f1dd16bd4b749dfb)) * disassembly prompt with source stock entry field ([c9d03d0](https://github.com/frappe/erpnext/commit/c9d03d049c57fdd41af00ea28fe292f511d41ec5)) * divide sub-assembly cost by qty to get per-unit rate in BOM Creator (backport [#54090](https://github.com/frappe/erpnext/issues/54090)) ([#54091](https://github.com/frappe/erpnext/issues/54091)) ([454271a](https://github.com/frappe/erpnext/commit/454271ad68073ad85e65e6029266c24548d5d94c)) * do not repost GL if no change in valuation ([89e3e3c](https://github.com/frappe/erpnext/commit/89e3e3c59e0a6e6ceaee5d3688018744dc4ec9cf)) * do not show inv dimension unnecessarily in stock entry (backport [#53946](https://github.com/frappe/erpnext/issues/53946)) ([#53951](https://github.com/frappe/erpnext/issues/53951)) ([573a1a0](https://github.com/frappe/erpnext/commit/573a1a0dcb7f11c35cfa75c18d23f71a6a2a41d2)) * dynamic labels on invoice type change ([4705f53](https://github.com/frappe/erpnext/commit/4705f53d2c53b597df3cd6e5a4bf5fd321cfcfbe)) * ensure accurate rounding for item-wise tax and taxable amounts ([c4c76cc](https://github.com/frappe/erpnext/commit/c4c76cc1b2e65f510d57fa65a3ef966454ef6266)) * GL entries for different exchange rate in the purchase invoice ([5719992](https://github.com/frappe/erpnext/commit/5719992cdaf836762e80ee14177f9ae9b1d2bbc9)) * handle disassembly for secondary / scrap items ([d50279b](https://github.com/frappe/erpnext/commit/d50279b718c195ba6f2735d448bc4736f3d4bfcd)) * hide fields related to track Semi-Finished Goods if feature has disabled ([5a7d0d2](https://github.com/frappe/erpnext/commit/5a7d0d2765c199d7ddd7b60c7d5c7f02dcee1ea8)) * include rejected qty in tax (purchase receipt) (backport [#53624](https://github.com/frappe/erpnext/issues/53624)) ([#53972](https://github.com/frappe/erpnext/issues/53972)) ([e230f72](https://github.com/frappe/erpnext/commit/e230f72e0ba93e49c8564c6f2ffb84b1659eb596)) * manufacture entry with group_by support ([31ac46a](https://github.com/frappe/erpnext/commit/31ac46ae4c04ce379def08dc2cadb84f5e5a1261)) * **manufacturing:** handle null cur_dialog in BOM work order dialog (backport [#54011](https://github.com/frappe/erpnext/issues/54011)) ([#54015](https://github.com/frappe/erpnext/issues/54015)) ([01610b2](https://github.com/frappe/erpnext/commit/01610b2fa7a0a772edf8a76399ebb0161012b3b5)) * Party Field only visibile when party type selected ([f42a1e8](https://github.com/frappe/erpnext/commit/f42a1e8a147b793cefb13eee45aeee0ed0085b80)) * prevent selection of group type customer group in customer master ([04cced2](https://github.com/frappe/erpnext/commit/04cced2fb5f8e34d67b23500c7eb0a5a69fef721)) * print hide unnecessary fields ([cd98312](https://github.com/frappe/erpnext/commit/cd983120834802b5a67c30fb0309183c14094f63)) * process loss with bom path disassembly ([0a257ea](https://github.com/frappe/erpnext/commit/0a257ea63d6820a49b13b713f1ffa6a4185ad479)) * **promotional_scheme:** toggle enable state between Buying and Selli… (backport [#54110](https://github.com/frappe/erpnext/issues/54110)) ([#54112](https://github.com/frappe/erpnext/issues/54112)) ([4a6fe47](https://github.com/frappe/erpnext/commit/4a6fe477d4e82efdb01a61f53d6ce15a76bafbc8)) * rejected serial no field showing even if serial / batch feature not enabled ([2c81f79](https://github.com/frappe/erpnext/commit/2c81f79df7d3a9d5ce88449a3533605d4dabc0e1)) * remove null from link_filters ([21f36f5](https://github.com/frappe/erpnext/commit/21f36f5c21dceeb7214d961fe8ff5731bd41106e)) * remove reference in serial/batch when document is cancelled (backport [#53979](https://github.com/frappe/erpnext/issues/53979)) ([#53989](https://github.com/frappe/erpnext/issues/53989)) ([5aaca83](https://github.com/frappe/erpnext/commit/5aaca83fe460500c73de4d3194891898580d72d3)) * remove title field from purchase receipt (backport [#54051](https://github.com/frappe/erpnext/issues/54051)) ([#54065](https://github.com/frappe/erpnext/issues/54065)) ([84382db](https://github.com/frappe/erpnext/commit/84382db5ca1911f40b8dec904477686ccc29cdff)) * remove unnecessary param, and use value from self ([7bef954](https://github.com/frappe/erpnext/commit/7bef9542d420fb89ed1dcf90345cbe409c08563e)) * resolve user permission error on status change by updating user … (backport [#54033](https://github.com/frappe/erpnext/issues/54033)) ([#54060](https://github.com/frappe/erpnext/issues/54060)) ([62b83ca](https://github.com/frappe/erpnext/commit/62b83cacce540a671b85d565d5d277090ba80a44)) * screen freezes if consumed qty set in SCR ([bd67ef8](https://github.com/frappe/erpnext/commit/bd67ef8d2652ea09155f30db3015eb6dc853fcfb)) * set bom details on disassembly; abs batch qty ([fb1d865](https://github.com/frappe/erpnext/commit/fb1d865e9b6b0f47e09ab9521bc7bf6b8c0efd9b)) * set serial and batch from source stock entry - on disassemble ([ff104ed](https://github.com/frappe/erpnext/commit/ff104edf1289dbf9876db11d8bdc95ecd9fb8d3b)) * set_query for source stock entry ([5f67ef7](https://github.com/frappe/erpnext/commit/5f67ef70bbc97c98b2ca3d9c220fa98270778371)) * show current stock qty in Stock Entry PDF (backport [#53761](https://github.com/frappe/erpnext/issues/53761)) ([#54032](https://github.com/frappe/erpnext/issues/54032)) ([ab08162](https://github.com/frappe/erpnext/commit/ab08162f34ce2cc1f68316757fbabd0cd59d17a1)) * skip discount amount validation when not saving ([8941699](https://github.com/frappe/erpnext/commit/8941699a34aa07103dd8e469ecc95b1aec26adb5)) * skip validate_stock_accounts in Journal Entry when perpetual inventory is disabled (backport [#53554](https://github.com/frappe/erpnext/issues/53554)) ([#53558](https://github.com/frappe/erpnext/issues/53558)) ([7062b71](https://github.com/frappe/erpnext/commit/7062b7153e8f4fc27c90533160b5b869816cc6b8)) * **stock:** update stock queue in SABE for return entries ([fc5a04d](https://github.com/frappe/erpnext/commit/fc5a04db2e92e92f05965b24ac5289ab3fa93163)) * support creating disassembly (without link of WO) ([1c4b2a7](https://github.com/frappe/erpnext/commit/1c4b2a7148527d7212c96be3b5eb3680d8571010)) * sync paid and received amount (backport [#53039](https://github.com/frappe/erpnext/issues/53039)) ([#54108](https://github.com/frappe/erpnext/issues/54108)) ([df3f242](https://github.com/frappe/erpnext/commit/df3f242331053d1412592e70048546f235b5b8f5)) * task gantt popup text not visible in light theme (backport [#53882](https://github.com/frappe/erpnext/issues/53882)) ([#54094](https://github.com/frappe/erpnext/issues/54094)) ([995a29e](https://github.com/frappe/erpnext/commit/995a29e3e1929a8da376cacafa5a53c4fb243e05)) * **taxes:** improve tax calculation accuracy and update test assertions ([6ad5e89](https://github.com/frappe/erpnext/commit/6ad5e8960782f761ce4dcca305c2c94ea88b11fc)) * **taxes:** increase rounding threshold for tax breakup calculations ([3592637](https://github.com/frappe/erpnext/commit/3592637b5c88249ff9c0a721eb7d8d3b7df646c6)) * **test:** do not use is_group enabled customer group in test ([8674aaf](https://github.com/frappe/erpnext/commit/8674aafc86897bd2cd4ede47bc2a0d0287e548cf)) * **tests:** update item code and quantity in tax detail test case ([6689b17](https://github.com/frappe/erpnext/commit/6689b17b882f2bd8e5ea3a7ac10aba9e90d90345)) * transactions where update stock is 0 should not create SLEs (backport [#54035](https://github.com/frappe/erpnext/issues/54035)) ([#54077](https://github.com/frappe/erpnext/issues/54077)) ([af81ed8](https://github.com/frappe/erpnext/commit/af81ed874b13c0bda088ff8728bab7524410c035)) * update min date based on transaction_date (backport [#53803](https://github.com/frappe/erpnext/issues/53803)) ([#54025](https://github.com/frappe/erpnext/issues/54025)) ([bc86e2c](https://github.com/frappe/erpnext/commit/bc86e2c1f2fe81a4638babb0690937c9d2e7b421)) * use get_value ([e4eb88d](https://github.com/frappe/erpnext/commit/e4eb88d80b3cdeb4124aa07ffba2868315904248)) * **ux:** refresh grid to correctly persist the state of fields ([273caa3](https://github.com/frappe/erpnext/commit/273caa38d99d90b9da6a3ed1b62108afc298336d)) * validate qty that can be disassembled from source stock entry. ([1237f9a](https://github.com/frappe/erpnext/commit/1237f9a0b17881f2f686bb715d1b7415094a4bf0)) * validate work order consistency in stock entry ([b030eea](https://github.com/frappe/erpnext/commit/b030eeafb8d920f32f84f7f4e62e84b607297c94)) * **warehouse_capacity_dashboard:** removed `escape` from template (backport [#53907](https://github.com/frappe/erpnext/issues/53907)) ([#53909](https://github.com/frappe/erpnext/issues/53909)) ([a478fb7](https://github.com/frappe/erpnext/commit/a478fb713139c0359c5b605581cabcc8a5352027)) ### Features * co product by product support ([#52979](https://github.com/frappe/erpnext/issues/52979)) ([#53975](https://github.com/frappe/erpnext/issues/53975)) ([8db397b](https://github.com/frappe/erpnext/commit/8db397bdae1f273d2f336abadafc4627469381d5)) * croatian_address_template (backport [#53888](https://github.com/frappe/erpnext/issues/53888)) ([#54058](https://github.com/frappe/erpnext/issues/54058)) ([ff26265](https://github.com/frappe/erpnext/commit/ff262655bb018a42bf1cc920534564e36476eeae)) * **Payment Request:** Added a toggle for using the payment schedule (backport [#53922](https://github.com/frappe/erpnext/issues/53922)) ([#53928](https://github.com/frappe/erpnext/issues/53928)) ([5ade905](https://github.com/frappe/erpnext/commit/5ade905ee85b92d724e1d7ba515cb9c70e24812c)) ### Performance Improvements * optimize account balance data fetching for Chart Of Accounts (backport [#53044](https://github.com/frappe/erpnext/issues/53044)) ([#53802](https://github.com/frappe/erpnext/issues/53802)) ([093ca87](https://github.com/frappe/erpnext/commit/093ca8745d9b9358ed5c163bb3ee675b56276f3f)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 92caee79427..172e697bbab 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.12.0" +__version__ = "16.13.0" def get_default_company(user=None): From 96446ed78d3307643a3b2852db9b4010b9b2bd63 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Wed, 8 Apr 2026 18:22:08 +0530 Subject: [PATCH 07/17] fix: last SLE not updated in the file (cherry picked from commit 38ed425ee299e70d8c22b759899f250fd5429393) (cherry picked from commit 60a1da0a1b10d751328afa8cfe1ba672c6c8699b) --- .../doctype/work_order/test_work_order.py | 18 +++++- erpnext/stock/stock_ledger.py | 59 ++++++++++--------- 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py index 8a13ed11fe2..b2a1eba0232 100644 --- a/erpnext/manufacturing/doctype/work_order/test_work_order.py +++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py @@ -518,9 +518,23 @@ class TestWorkOrder(ERPNextTestSuite): 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": "_Test Operation 1", - "workstation": "_Test Workstation 1", + "operation": operation_name, + "workstation": workstation_name, "description": "Test Data", "operating_cost": 100, "time_in_mins": 40, diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index f754cab7650..5bc799acdbe 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -267,17 +267,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) @@ -292,15 +286,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.in_test: frappe.db.commit() @@ -584,13 +577,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() @@ -625,8 +614,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) @@ -634,10 +634,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) @@ -651,7 +654,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): @@ -733,7 +736,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.in_test: @@ -990,6 +992,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 62448d98def6fc6a195686d16bc66474dd05a6cf Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Thu, 9 Apr 2026 04:50:03 +0000 Subject: [PATCH 08/17] chore(release): Bumped to Version 16.13.1 ## [16.13.1](https://github.com/frappe/erpnext/compare/v16.13.0...v16.13.1) (2026-04-09) ### Bug Fixes * last SLE not updated in the file ([96446ed](https://github.com/frappe/erpnext/commit/96446ed78d3307643a3b2852db9b4010b9b2bd63)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 172e697bbab..5d54b093319 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.13.0" +__version__ = "16.13.1" def get_default_company(user=None): From 3ce6dcc7a7b873e350fc1c82114b7b18f391e63b Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Thu, 9 Apr 2026 12:47:36 +0530 Subject: [PATCH 09/17] fix: set default posting time in RIV (cherry picked from commit a7ece65536d54c03a615ba43b5f23e4643492d6b) (cherry picked from commit 1086a7237317e9d2622d52d207949f7a7f66343b) --- .../repost_item_valuation/repost_item_valuation.py | 8 ++++++++ erpnext/stock/stock_ledger.py | 2 ++ 2 files changed, 10 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 84cf6234dcf..c63c2d34916 100644 --- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py +++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py @@ -80,6 +80,7 @@ class RepostItemValuation(Document): repost(self) def validate(self): + self.set_default_posting_time() self.reset_repost_only_accounting_ledgers() self.set_company() self.validate_update_stock() @@ -90,6 +91,13 @@ class RepostItemValuation(Document): self.reset_recreate_stock_ledgers() self.validate_recreate_stock_ledgers() + 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 diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py index 5bc799acdbe..c1a2cdb57b1 100644 --- a/erpnext/stock/stock_ledger.py +++ b/erpnext/stock/stock_ledger.py @@ -237,6 +237,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 c98ded52b2d19991a286097ecf9e2ad6332782e9 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Thu, 9 Apr 2026 09:59:33 +0000 Subject: [PATCH 10/17] chore(release): Bumped to Version 16.13.2 ## [16.13.2](https://github.com/frappe/erpnext/compare/v16.13.1...v16.13.2) (2026-04-09) ### Bug Fixes * set default posting time in RIV ([3ce6dcc](https://github.com/frappe/erpnext/commit/3ce6dcc7a7b873e350fc1c82114b7b18f391e63b)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 5d54b093319..6d221e5bbc4 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.13.1" +__version__ = "16.13.2" def get_default_company(user=None): From 93ede5b7646e34b20710cb1087ce22ad053c3d2f Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Sat, 11 Apr 2026 10:33:45 +0530 Subject: [PATCH 11/17] fix: timer not showing in job card (backport #53839) (backport #54212) (#54213) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Rohit Waghchaure fix: timer not showing in job card (backport #53839) (#54212) --- erpnext/manufacturing/doctype/job_card/job_card.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js index 68d1e3e6214..19132ecf9fd 100644 --- a/erpnext/manufacturing/doctype/job_card/job_card.js +++ b/erpnext/manufacturing/doctype/job_card/job_card.js @@ -278,6 +278,8 @@ frappe.ui.form.on("Job Card", { frm.trigger("complete_job_card"); }); } + + frm.trigger("make_dashboard"); } } From a1c43ae9133647cfec29487f54d8980af4d5e614 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Sat, 11 Apr 2026 05:05:14 +0000 Subject: [PATCH 12/17] chore(release): Bumped to Version 16.13.3 ## [16.13.3](https://github.com/frappe/erpnext/compare/v16.13.2...v16.13.3) (2026-04-11) ### Bug Fixes * timer not showing in job card (backport [#53839](https://github.com/frappe/erpnext/issues/53839)) (backport [#54212](https://github.com/frappe/erpnext/issues/54212)) ([#54213](https://github.com/frappe/erpnext/issues/54213)) ([93ede5b](https://github.com/frappe/erpnext/commit/93ede5b7646e34b20710cb1087ce22ad053c3d2f)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 6d221e5bbc4..8ce1d061001 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.13.2" +__version__ = "16.13.3" def get_default_company(user=None): From 9312781dcd1bb7b0cf35d96b7c816013addfa28a Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Tue, 14 Apr 2026 18:28:38 +0000 Subject: [PATCH 13/17] chore(release): Bumped to Version 16.14.0 # [16.14.0](https://github.com/frappe/erpnext/compare/v16.13.3...v16.14.0) (2026-04-14) ### Bug Fixes * account change in warehouse (backport [#54182](https://github.com/frappe/erpnext/issues/54182)) ([#54205](https://github.com/frappe/erpnext/issues/54205)) ([b42e239](https://github.com/frappe/erpnext/commit/b42e23993d6fed5f56b6a9847bd2f5f170f17515)) * add closing div tab ([7e5297a](https://github.com/frappe/erpnext/commit/7e5297a305fdd866e05d16dcb9d9a29691f55c72)) * add drop ship logic in gross profit report (backport [#54220](https://github.com/frappe/erpnext/issues/54220)) ([#54277](https://github.com/frappe/erpnext/issues/54277)) ([bd6269b](https://github.com/frappe/erpnext/commit/bd6269b9e75b23450c99db59ff62398087e3e679)) * add permission validation when prompting company details for incomplete letterhead data ([f2450ea](https://github.com/frappe/erpnext/commit/f2450eaf60246b4b9472062ed327527ffae35b7a)) * add quotation print format in the list ([bb77018](https://github.com/frappe/erpnext/commit/bb77018f7b0e96886c5252dbfd73f563c97eb3c1)) * banner to enable serial / batch feature ([dea2d21](https://github.com/frappe/erpnext/commit/dea2d21580bcd5459bf5e7b5d565f577fffb7d59)) * batch/serial should use parent's posting datetime for naming (backport [#54206](https://github.com/frappe/erpnext/issues/54206)) ([#54209](https://github.com/frappe/erpnext/issues/54209)) ([3bdac5c](https://github.com/frappe/erpnext/commit/3bdac5c30a563bb6b565d603192972aeccaed5cf)) * conflicting issue ([57e458c](https://github.com/frappe/erpnext/commit/57e458cc1eee41d46bfe8767828f0a71737aae70)) * conflicting issue ([29be73c](https://github.com/frappe/erpnext/commit/29be73c25641024599bc3782710e2d87936cf343)) * fetch correct expense account for operations in stock entry (backport [#54278](https://github.com/frappe/erpnext/issues/54278)) ([#54281](https://github.com/frappe/erpnext/issues/54281)) ([63ec36a](https://github.com/frappe/erpnext/commit/63ec36a6f9e52858a5b219572f8ad6296b605e53)) * handle multi uom conversion factor for manufacture entry (backport [#54285](https://github.com/frappe/erpnext/issues/54285)) ([#54286](https://github.com/frappe/erpnext/issues/54286)) ([d5143ed](https://github.com/frappe/erpnext/commit/d5143edccec5279569ea25a51fdc9208ab498f62)) * hardcoded precision causing decimal issues ([e361afb](https://github.com/frappe/erpnext/commit/e361afb6bcf1ea0eeb2e0a46b98f7a6c9b3d2a25)) * inventory dimension patch (backport [#54141](https://github.com/frappe/erpnext/issues/54141)) ([#54146](https://github.com/frappe/erpnext/issues/54146)) ([f2b3ade](https://github.com/frappe/erpnext/commit/f2b3adec0fbcb3311669a78936ac64613d92db4c)) * inventory dimension patch (backport [#54147](https://github.com/frappe/erpnext/issues/54147)) ([#54149](https://github.com/frappe/erpnext/issues/54149)) ([943ddff](https://github.com/frappe/erpnext/commit/943ddff6aacff7d0ec6f8893c8738651f6070893)) * inventory dimensions should not be mandatory unnecesarily (backport [#54064](https://github.com/frappe/erpnext/issues/54064)) ([#54134](https://github.com/frappe/erpnext/issues/54134)) ([7b0d34e](https://github.com/frappe/erpnext/commit/7b0d34e97941ef304ebf19f406068fcc6781f6e6)) * last SLE not updated in the file ([60a1da0](https://github.com/frappe/erpnext/commit/60a1da0a1b10d751328afa8cfe1ba672c6c8699b)) * make operation mandatory when any sub operation row is added (backport [#54245](https://github.com/frappe/erpnext/issues/54245)) ([#54248](https://github.com/frappe/erpnext/issues/54248)) ([394eb93](https://github.com/frappe/erpnext/commit/394eb93677b04a61e7c5c000d3f0ab4b332bcfbf)) * **manufacturing:** check remaining qty to calculate operating cost (backport [#53983](https://github.com/frappe/erpnext/issues/53983)) ([#54128](https://github.com/frappe/erpnext/issues/54128)) ([856ba24](https://github.com/frappe/erpnext/commit/856ba2419462a94e21a89668e9f113865c07c1a8)) * not able to submit the PO (backport [#54257](https://github.com/frappe/erpnext/issues/54257)) ([#54261](https://github.com/frappe/erpnext/issues/54261)) ([9d90fc4](https://github.com/frappe/erpnext/commit/9d90fc4a8451bc333bd27d98af753a29d8c3f7d4)) * preserve asset movement field properties after save ([b7f1677](https://github.com/frappe/erpnext/commit/b7f1677eef6a90e272131c279299e408883cbcbc)) * quality inspection item code fetch perm issue (backport [#54121](https://github.com/frappe/erpnext/issues/54121)) ([#54127](https://github.com/frappe/erpnext/issues/54127)) ([9d31712](https://github.com/frappe/erpnext/commit/9d317129f4c51ba3ac51c44966b5e4463e754e3d)) * remove unneccessary function for serial no status updation (backport [#54191](https://github.com/frappe/erpnext/issues/54191)) ([#54197](https://github.com/frappe/erpnext/issues/54197)) ([4e828fd](https://github.com/frappe/erpnext/commit/4e828fd897557145237eb697475e312889e47ff5)) * remove unused print format ([f5a9657](https://github.com/frappe/erpnext/commit/f5a9657a91f12231b615661d7d57b76e34ef1d5c)) * replace raw SQL with qb in get_against_jv to prevent SQL injection ([8f86a28](https://github.com/frappe/erpnext/commit/8f86a2879c05cdbc5f0813d4a4326eaac0f88321)) * **sales invoice:** toggle Get Items From button based on is_return and POS view (backport [#52594](https://github.com/frappe/erpnext/issues/52594)) ([#54139](https://github.com/frappe/erpnext/issues/54139)) ([fe2161e](https://github.com/frappe/erpnext/commit/fe2161ea0cd5b479dd6aaf0d120efb6cd54b3133)) * **selling:** enable selling_settings creation through fixtures (backport [#54177](https://github.com/frappe/erpnext/issues/54177)) ([#54215](https://github.com/frappe/erpnext/issues/54215)) ([d2745f3](https://github.com/frappe/erpnext/commit/d2745f3ec907b7b7b95fc6a3d634389c0ca4fb16)) * set default posting time in RIV ([1086a72](https://github.com/frappe/erpnext/commit/1086a7237317e9d2622d52d207949f7a7f66343b)) * Set remarks blank instead of No remarks in Sales/Purchase Invoices ([a71814a](https://github.com/frappe/erpnext/commit/a71814a483d1056fb50c4be7412210d2cada7374)) * **stock:** ignore delivery note on delivery trip on_cancel trigger (backport [#54120](https://github.com/frappe/erpnext/issues/54120)) ([#54123](https://github.com/frappe/erpnext/issues/54123)) ([864a7fd](https://github.com/frappe/erpnext/commit/864a7fdab5fd3953929a80776ba80a0587866f44)) * **stock:** remove float precision to fix precision issue (backport [#54284](https://github.com/frappe/erpnext/issues/54284)) ([#54289](https://github.com/frappe/erpnext/issues/54289)) ([6e3549d](https://github.com/frappe/erpnext/commit/6e3549d1852a8408d829582c4665548a98591425)) * **stock:** update bin to zero when no previous sle exists (backport [#54236](https://github.com/frappe/erpnext/issues/54236)) ([#54264](https://github.com/frappe/erpnext/issues/54264)) ([2c292f4](https://github.com/frappe/erpnext/commit/2c292f4770b6daee1b7c4c84f938c96af43fd823)) * **test:** Remove usage of No remark as remark in tests ([6993255](https://github.com/frappe/erpnext/commit/699325506f76d74d60a0ea9d63ed10015666c3aa)) * timer not showing in job card (backport [#53839](https://github.com/frappe/erpnext/issues/53839)) ([#54212](https://github.com/frappe/erpnext/issues/54212)) ([7d8f59e](https://github.com/frappe/erpnext/commit/7d8f59eb0a70a5d91b4d0987d562f02d3fa4f7a9)) * update return value in workstation list view indicator (backport [#54198](https://github.com/frappe/erpnext/issues/54198)) ([#54201](https://github.com/frappe/erpnext/issues/54201)) ([22774fd](https://github.com/frappe/erpnext/commit/22774fd81071ae8ad31ef15b97868f336b91850e)) * update_nsm only in warehouse creation ([#54165](https://github.com/frappe/erpnext/issues/54165)) ([abb896e](https://github.com/frappe/erpnext/commit/abb896ecf1e7336ddda7b9a993134dc6cefb440c)) * wrong operation time calculation (backport [#53796](https://github.com/frappe/erpnext/issues/53796)) ([#54274](https://github.com/frappe/erpnext/issues/54274)) ([d0bff47](https://github.com/frappe/erpnext/commit/d0bff472729110c741498c1e559dc3da8d0419c9)) ### Features * Allowing operation level quality inspection check in BOM (backport [#53859](https://github.com/frappe/erpnext/issues/53859)) ([#54144](https://github.com/frappe/erpnext/issues/54144)) ([233dc7c](https://github.com/frappe/erpnext/commit/233dc7c07bf02344dfe27113ec193ea6a7d22ef5)) * default print format for Quotation ([a8769bf](https://github.com/frappe/erpnext/commit/a8769bfb772edef671c97264d46ac02409890ec6)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 8ce1d061001..2b26db9be93 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.13.3" +__version__ = "16.14.0" def get_default_company(user=None): From c99b9e1b64eb357066b87841c2bd3f2170fe5ad7 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Wed, 22 Apr 2026 00:21:02 +0000 Subject: [PATCH 14/17] chore(release): Bumped to Version 16.15.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # [16.15.0](https://github.com/frappe/erpnext/compare/v16.14.0...v16.15.0) (2026-04-22) ### Bug Fixes * **accounts:** fetch project name from payment entry to journal entry (backport [#54307](https://github.com/frappe/erpnext/issues/54307)) ([#54453](https://github.com/frappe/erpnext/issues/54453)) ([62a9a76](https://github.com/frappe/erpnext/commit/62a9a761b755f3045d294b149dbc107475b74368)) * add portal user ownership check to supplier quotation (backport [#54298](https://github.com/frappe/erpnext/issues/54298)) ([#54300](https://github.com/frappe/erpnext/issues/54300)) ([d7da5b0](https://github.com/frappe/erpnext/commit/d7da5b047d5b7cf69da15d4269681c1fbff19957)) * add project filter to accounts payable and receivable reports (backport [#54344](https://github.com/frappe/erpnext/issues/54344)) ([#54442](https://github.com/frappe/erpnext/issues/54442)) ([57cd2a0](https://github.com/frappe/erpnext/commit/57cd2a06e843147d040fe6d36e6128515f5217d3)) * append row level user remarks in gl map ([aa359ad](https://github.com/frappe/erpnext/commit/aa359aded4f7817b1a2830b4cbeabb99817f42c3)) * changed qty validation from qty field to stock_qty (backport [#54352](https://github.com/frappe/erpnext/issues/54352)) ([#54357](https://github.com/frappe/erpnext/issues/54357)) ([fa76e8a](https://github.com/frappe/erpnext/commit/fa76e8ac7f89fd43d54ab78cbe9ec96a925095d8)) * clear conditions table when calculate_based_on is set to Fixed ([7849733](https://github.com/frappe/erpnext/commit/78497336c7c71ca8c7f202441c9902e3609b07ff)) * clear shipping rule conditions for fixed shipping rule ([319d769](https://github.com/frappe/erpnext/commit/319d769c6f256338fd7e00cb4fbb3017080bcfb4)) * **dashboard-trends:** set default fiscal year and company before val… (backport [#54339](https://github.com/frappe/erpnext/issues/54339)) ([#54400](https://github.com/frappe/erpnext/issues/54400)) ([b1825c0](https://github.com/frappe/erpnext/commit/b1825c0cbeb5bfc69468c7684770bc8ecaf45f78)) * default company perms for HR manager ([47abaf7](https://github.com/frappe/erpnext/commit/47abaf70b24b588aad481df30afe4b799934f556)) * default perm for HR manager & HR user ([95213fb](https://github.com/frappe/erpnext/commit/95213fb9b830b7de9e324d7724867633804fbca4)) * default perm for HR manager & HR user ([a7b1fec](https://github.com/frappe/erpnext/commit/a7b1fec21dcb4609cab5f62a02926efc7232227c)) * default permission for HR manager role ([534891a](https://github.com/frappe/erpnext/commit/534891aac4b291bd2e510cada37367cc1dffb8ad)) * default permission for HR User role ([0d6d64f](https://github.com/frappe/erpnext/commit/0d6d64ff0571e65734460e969bc16c2d0af62527)) * Disallow negative rates in Purchase invoice (backport [#54254](https://github.com/frappe/erpnext/issues/54254)) ([#54393](https://github.com/frappe/erpnext/issues/54393)) ([cac9073](https://github.com/frappe/erpnext/commit/cac907383b9906496b9d8220a9be9bc863bc29ca)) * dropship logic should come above non stock logic in gross profit… (backport [#54383](https://github.com/frappe/erpnext/issues/54383)) ([#54385](https://github.com/frappe/erpnext/issues/54385)) ([78aaf6c](https://github.com/frappe/erpnext/commit/78aaf6c7e83cd92fe7feac42c661cb04d6a38267)) * fetch item tax template from item group when creating item (backport [#54258](https://github.com/frappe/erpnext/issues/54258)) ([#54368](https://github.com/frappe/erpnext/issues/54368)) ([3914d5d](https://github.com/frappe/erpnext/commit/3914d5d1b736738e9bdacd5f9f3c81b12491056f)) * hide operations field in bom creator if phantom (backport [#54336](https://github.com/frappe/erpnext/issues/54336)) ([#54337](https://github.com/frappe/erpnext/issues/54337)) ([b252ad4](https://github.com/frappe/erpnext/commit/b252ad49b7484486bbd1c465fe9200f373f134cc)) * make Target Warehouse mandatory on UI ([46f5de0](https://github.com/frappe/erpnext/commit/46f5de0b1c4c2604bf54b21069b7de76e5aab099)) * **manufacturing:** handle empty list in query builder ([d2cc549](https://github.com/frappe/erpnext/commit/d2cc54969651d35df316fa4621fda6246f0cdc25)) * move make_dimension_in_accounting_doctypes from after_insert to on_update ([f287edd](https://github.com/frappe/erpnext/commit/f287edd8c26583bc043c76316e12cfe38df3a200)) * negative batch report showing same batch-warehouse multiple times ([493f36b](https://github.com/frappe/erpnext/commit/493f36b3cee01bd1574a17d0dbbc5926384d080c)) * non-collapsible in customer quick entry ([101f68c](https://github.com/frappe/erpnext/commit/101f68c8e8f13177f014f5ae84c793ef29eb07e5)) * **pos_invoice_item:** fetch `grant_commission` from `item_code` (backport [#54413](https://github.com/frappe/erpnext/issues/54413)) ([#54418](https://github.com/frappe/erpnext/issues/54418)) ([dd6d4d1](https://github.com/frappe/erpnext/commit/dd6d4d19103cefef56a3f34a6295a8fe7d5842bb)) * **purchase_register:** filter tax rows by parenttype in invoice tax map query (backport [#54272](https://github.com/frappe/erpnext/issues/54272)) ([#54444](https://github.com/frappe/erpnext/issues/54444)) ([01aff64](https://github.com/frappe/erpnext/commit/01aff6492c16bb9a3fdb45420aa187fd72a472dc)) * recalculate operating costs if workstation type is changed (backport [#54390](https://github.com/frappe/erpnext/issues/54390)) ([#54398](https://github.com/frappe/erpnext/issues/54398)) ([cfcba1f](https://github.com/frappe/erpnext/commit/cfcba1fcf24af5d10e05c24955024231432d39d5)) * remove unwanted perm for HR user role ([4940aeb](https://github.com/frappe/erpnext/commit/4940aeb71212bb37726b0443dcced964be794e03)) * reset base_rounded_total when rounded_total resets (backport [#54241](https://github.com/frappe/erpnext/issues/54241)) ([#54304](https://github.com/frappe/erpnext/issues/54304)) ([45052ce](https://github.com/frappe/erpnext/commit/45052ce8a74800b4ef4d2080bfba3c1dba30c928)) * resolve conflict ([9e6300b](https://github.com/frappe/erpnext/commit/9e6300bf76b8534d52296f0725a71686e677f541)) * sales order is not valid when creating WO from MR from PP (backport [#54435](https://github.com/frappe/erpnext/issues/54435)) ([#54436](https://github.com/frappe/erpnext/issues/54436)) ([5397b7d](https://github.com/frappe/erpnext/commit/5397b7da25ad7032f29392dbef97f6f7acac3747)) * Table row in dialog should not have delete row option ([5916e57](https://github.com/frappe/erpnext/commit/5916e570af92109833da237ecd9a360516f9a976)) * **taxes_and_totals:** apply conversion_rate to taxable_amount in get_itemised_tax ([d506e57](https://github.com/frappe/erpnext/commit/d506e574d26cee1d1027567ba676cada0d83fe2b)) * **test:** missing repost allowed defaults ([d49c343](https://github.com/frappe/erpnext/commit/d49c34389b579462eebb60f627e87877166b2241)) * use qty instead of stock qty dropship gross profit report (backport [#54389](https://github.com/frappe/erpnext/issues/54389)) ([#54391](https://github.com/frappe/erpnext/issues/54391)) ([7556550](https://github.com/frappe/erpnext/commit/7556550158d26f3744e4e3d2ed81218cd822668f)) * validate south africa company in vat audit report (backport [#54030](https://github.com/frappe/erpnext/issues/54030)) ([#54394](https://github.com/frappe/erpnext/issues/54394)) ([aa2cba9](https://github.com/frappe/erpnext/commit/aa2cba97808cdebb227c067504317e41922ded3a)) * zero valuation rate popup on SI (backport [#54376](https://github.com/frappe/erpnext/issues/54376)) ([#54377](https://github.com/frappe/erpnext/issues/54377)) ([104eac2](https://github.com/frappe/erpnext/commit/104eac21e8f3c4a4fb01304b514fe2fdba30ff39)) ### Features * add option to create production plan from sales order (backport [#53662](https://github.com/frappe/erpnext/issues/53662)) ([#54323](https://github.com/frappe/erpnext/issues/54323)) ([b487f69](https://github.com/frappe/erpnext/commit/b487f69b594da886c5eb501ef60d076e51781528)) * add support for 'not applicable' tax in item tax templates ([#50898](https://github.com/frappe/erpnext/issues/50898)) ([52a4ca9](https://github.com/frappe/erpnext/commit/52a4ca9c410fc320988a9ce1b90bd4782e215cdf)) * backflush based on in BOM ([2c73e37](https://github.com/frappe/erpnext/commit/2c73e37f8025caf483d7022f2d196de50146f8d4)) * make fg phantom-able in bom creator (backport [#54332](https://github.com/frappe/erpnext/issues/54332)) ([#54333](https://github.com/frappe/erpnext/issues/54333)) ([10dbfd3](https://github.com/frappe/erpnext/commit/10dbfd310f4c27ae17990c869766ea97f8aa1529)) * use single remark field with custom remark toggle ([27c5dab](https://github.com/frappe/erpnext/commit/27c5dab7e462f6db89d4c2e283dea92e5cd670d0)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index 2b26db9be93..e0843a4d073 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.14.0" +__version__ = "16.15.0" def get_default_company(user=None): From 610735d1c50003c0022a8ea0fea4fb1464709694 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 12:33:34 +0000 Subject: [PATCH 15/17] fix: preserve inventory dimensions when raw materials are reset (backport #54440) (backport #54493) (#54513) * fix: preserve inventory dimensions when raw materials are reset (backport #54440) (#54493) fix: preserve inventory dimensions when raw materials are reset (#54440) * fix: preserve inventory dimensions when raw materials are reset * test: add test case (cherry picked from commit 0e20e35842bf090241d7b296c19f2714b6fd2588) Co-authored-by: Mihir Kandoi (cherry picked from commit 456e99b3521d16b7c127edff6d1c5cbdc103d865) # Conflicts: # erpnext/patches.txt * chore: resolve conflicts --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Mihir Kandoi --- erpnext/patches.txt | 1 + erpnext/patches/v16_0/scr_inv_dimension.py | 24 +++++++++++ .../inventory_dimension.py | 15 +++++-- .../test_inventory_dimension.py | 1 - .../subcontracting_receipt.js | 6 +++ .../subcontracting_receipt.py | 32 +++++++++++++++ .../test_subcontracting_receipt.py | 41 +++++++++++++++++++ 7 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 erpnext/patches/v16_0/scr_inv_dimension.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 61b93b292b1..e339a85bf70 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -476,3 +476,4 @@ erpnext.patches.v16_0.co_by_product_patch erpnext.patches.v16_0.depends_on_inv_dimensions erpnext.patches.v16_0.uom_category erpnext.patches.v16_0.merge_repost_settings_to_accounts_settings +erpnext.patches.v16_0.scr_inv_dimension diff --git a/erpnext/patches/v16_0/scr_inv_dimension.py b/erpnext/patches/v16_0/scr_inv_dimension.py new file mode 100644 index 00000000000..f4b320f674b --- /dev/null +++ b/erpnext/patches/v16_0/scr_inv_dimension.py @@ -0,0 +1,24 @@ +import frappe + +from erpnext.stock.doctype.inventory_dimension.inventory_dimension import get_inventory_dimensions + + +def execute(): + for dimension in get_inventory_dimensions(): + if frappe.db.exists( + "Custom Field", + { + "fieldname": dimension.source_fieldname, + "dt": "Subcontracting Receipt Supplied Item", + "reqd": 1, + }, + ): + frappe.set_value( + "Custom Field", + { + "fieldname": dimension.source_fieldname, + "dt": "Subcontracting Receipt Supplied Item", + "reqd": 1, + }, + {"reqd": 0, "mandatory_depends_on": "eval:doc.reference_name"}, + ) diff --git a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py index fc5038db069..86ce5c3eb85 100644 --- a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py +++ b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py @@ -167,6 +167,13 @@ class InventoryDimension(Document): if label_start_with: label = f"{label_start_with} {self.dimension_name}" + mandatory_depends_on = self.mandatory_depends_on + if self.reqd: + if doctype == "Stock Entry Detail": + mandatory_depends_on = "eval:doc.s_warehouse" + elif doctype == "Subcontracting Receipt Supplied Item": + mandatory_depends_on = "eval:doc.reference_name" + dimension_fields = [ dict( fieldname="inventory_dimension", @@ -184,11 +191,11 @@ class InventoryDimension(Document): depends_on="eval:doc.s_warehouse" if doctype == "Stock Entry Detail" else "", search_index=1, reqd=1 - if self.reqd and not self.mandatory_depends_on and doctype != "Stock Entry Detail" + if self.reqd + and not self.mandatory_depends_on + and doctype not in ["Stock Entry Detail", "Subcontracting Receipt Supplied Item"] else 0, - mandatory_depends_on="eval:doc.s_warehouse" - if self.reqd and doctype == "Stock Entry Detail" - else self.mandatory_depends_on, + mandatory_depends_on=mandatory_depends_on, ), ] diff --git a/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py b/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py index bfe6864486b..2a69c450b3d 100644 --- a/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py +++ b/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py @@ -225,7 +225,6 @@ class TestInventoryDimension(ERPNextTestSuite): ) ) - doc.load_from_db doc.reqd = 0 doc.save() diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js index 5bb7c2f0cc2..0c2a10705c4 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js @@ -435,6 +435,12 @@ frappe.ui.form.on("Subcontracting Receipt Item", { set_missing_values(frm); }, + before_items_remove(frm, cdt, cdn) { + const filtered_rows = frm.doc.supplied_items.filter((item) => item.reference_name !== cdn); + frm.doc.supplied_items = filtered_rows; + frm.refresh_field("supplied_items"); + }, + items_delete(frm) { set_missing_values(frm); }, diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py index 664adf254f8..23a3830c951 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py @@ -15,6 +15,7 @@ from erpnext.buying.utils import check_on_hold_or_closed_status from erpnext.controllers.subcontracting_controller import SubcontractingController from erpnext.setup.doctype.brand.brand import get_brand_defaults from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults +from erpnext.stock.doctype.inventory_dimension.inventory_dimension import get_inventory_dimensions from erpnext.stock.doctype.item.item import get_item_defaults from erpnext.stock.get_item_details import get_default_cost_center, get_default_expense_account from erpnext.stock.stock_ledger import get_valuation_rate @@ -119,6 +120,7 @@ class SubcontractingReceipt(SubcontractingController): ) def before_validate(self): + self.save_inventory_dimensions() super().before_validate() self.validate_items_qty() self.set_items_bom() @@ -159,6 +161,7 @@ class SubcontractingReceipt(SubcontractingController): self.set_supplied_items_expense_account() self.set_supplied_items_cost_center() + self.set_supplied_items_inventory_dimensions() def on_submit(self): self.validate_closed_subcontracting_order() @@ -312,6 +315,22 @@ class SubcontractingReceipt(SubcontractingController): self.company, ) + def set_supplied_items_inventory_dimensions(self): + if hasattr(self, "inventory_dimensions") and (inventory_dimensions := get_inventory_dimensions()): + for item in self.supplied_items: + key = ( + item.reference_name, + item.rm_item_code, + item.main_item_code, + item.batch_no, + item.serial_no, + ) + + for dimension in inventory_dimensions: + dimension_values = self.inventory_dimensions.get(dimension.source_fieldname, {}) + if key in dimension_values: + item.set(dimension.source_fieldname, dimension_values[key]) + def set_supplied_items_expense_account(self): for item in self.supplied_items: if not item.expense_account: @@ -328,6 +347,19 @@ class SubcontractingReceipt(SubcontractingController): get_brand_defaults(item.rm_item_code, self.company), ) + def save_inventory_dimensions(self): + if inventory_dimensions := get_inventory_dimensions(): + if not getattr(self, "inventory_dimensions", None): + self.inventory_dimensions = {} + + for dimension in inventory_dimensions: + self.inventory_dimensions[dimension.source_fieldname] = { + (d.reference_name, d.rm_item_code, d.main_item_code, d.batch_no, d.serial_no): d.get( + dimension.source_fieldname + ) + for d in self.supplied_items + } + def reset_supplied_items(self): if ( frappe.db.get_single_value("Buying Settings", "backflush_raw_materials_of_subcontract_based_on") diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py index b4b0c930082..7105eca2e13 100644 --- a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py +++ b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py @@ -2036,6 +2036,47 @@ class TestSubcontractingReceipt(ERPNextTestSuite): scr.submit() frappe.flags["args"].pop("items", None) + def test_inventory_dimensions(self): + """ + The subcontracting controller resets the supplied items table on each save causing the inventory dimensions to be lost. + This test ensures that the inventory dimensions are retained on each save. + """ + from erpnext.stock.doctype.inventory_dimension.test_inventory_dimension import ( + create_inventory_dimension, + ) + + inventory_dimension = create_inventory_dimension( + apply_to_all_doctypes=1, + dimension_name="Inv Site", + reference_document="Inv Site", + document_type="Inv Site", + ) + + inventory_dimension.reqd = 1 + inventory_dimension.save() + + set_backflush_based_on("BOM") + + sco = get_subcontracting_order() + rm_items = get_rm_items(sco.supplied_items) + itemwise_details = make_stock_in_entry(rm_items=rm_items) + make_stock_transfer_entry( + sco_no=sco.name, + rm_items=rm_items, + itemwise_details=copy.deepcopy(itemwise_details), + ) + scr = make_subcontracting_receipt(sco.name) + scr.items[0].inv_site = "Site 1" + scr.save() + + scr.supplied_items[0].inv_site = "Site 1" + scr.save() + + self.assertEqual(scr.supplied_items[0].inv_site, "Site 1") + + inventory_dimension.reqd = 0 + inventory_dimension.save() + def make_return_subcontracting_receipt(**args): args = frappe._dict(args) From 66ec6a4d2031f65b2403e646aff0f5a58c1cd957 Mon Sep 17 00:00:00 2001 From: Frappe PR Bot Date: Fri, 24 Apr 2026 12:35:07 +0000 Subject: [PATCH 16/17] chore(release): Bumped to Version 16.15.1 ## [16.15.1](https://github.com/frappe/erpnext/compare/v16.15.0...v16.15.1) (2026-04-24) ### Bug Fixes * preserve inventory dimensions when raw materials are reset (backport [#54440](https://github.com/frappe/erpnext/issues/54440)) (backport [#54493](https://github.com/frappe/erpnext/issues/54493)) ([#54513](https://github.com/frappe/erpnext/issues/54513)) ([610735d](https://github.com/frappe/erpnext/commit/610735d1c50003c0022a8ea0fea4fb1464709694)) --- erpnext/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/__init__.py b/erpnext/__init__.py index e0843a4d073..be5aa72a516 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -6,7 +6,7 @@ import frappe from frappe.model.document import Document from frappe.utils.user import is_website_user -__version__ = "16.15.0" +__version__ = "16.15.1" def get_default_company(user=None): From 764c775e1910a0daa360fd28b0ecf635ad07604d Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 14:39:42 +0000 Subject: [PATCH 17/17] refactor: tax witholding report (backport #54449) (backport #54477) (#54519) * refactor: use consistent report column names (cherry picked from commit 6dca96b423887da5464d482a1cbad1bbd34517a2) (cherry picked from commit 9276cd7343ac4788b564345de8011d457ad73e50) * refactor: how data is built (cherry picked from commit c3e7f7f02f9fabdbfc579ae0498350b1ad21857f) (cherry picked from commit be0e58fb234adc24c562b877c85d7ff66fcd0d19) * refactor: better label for entity type (cherry picked from commit 53666974a354166c4a4f69ab8f1d99742660f79a) (cherry picked from commit fffaf834fd477368bf686031c5ad2ace7296d608) * refactor: updated key for withholding_date (cherry picked from commit 07b023a934d85f3b209de2c8c714ac427e2bc1e8) (cherry picked from commit e6cfdb8e4deebe05360eed50d69d0af6019d063f) * test: None is better than zero, as no values exist (cherry picked from commit b5550f747ed84f19d6ade02e28979dc480cc4696) (cherry picked from commit 40466be9ef6ec159385aa1d867af3ddbdd25b45a) * refactor: make report extensible by regional apps (cherry picked from commit f0ea20e579c1fab4dd479a39bde1d0e25b9593fb) (cherry picked from commit 6392126ca5328b06d1509e7dabdfbbb29743eae8) * fix: add party type for dynamic link support (cherry picked from commit b925469c4d1ddb9c482b7506c1ec554c54838275) (cherry picked from commit c6d48028576e726d1e8c1977f06f04ceafaed2a9) --------- Co-authored-by: Smit Vora --- .../tax_withholding_details.py | 521 +++++++++--------- .../test_tax_withholding_details.py | 4 +- .../tds_computation_summary.py | 177 +++--- 3 files changed, 328 insertions(+), 374 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 70813aaeb1d..554a669512a 100644 --- a/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py +++ b/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py @@ -6,301 +6,282 @@ from frappe import _ from frappe.query_builder.functions import IfNull -def execute(filters=None): - """Generate Tax Withholding Details report""" - validate_filters(filters) +class TaxWithholdingDetailsReport: + party_types = ("Customer", "Supplier") + document_types = ("Purchase Invoice", "Sales Invoice", "Payment Entry", "Journal Entry") - # Process and format data - data = get_tax_withholding_data(filters) - columns = get_columns(filters) + def __init__(self, filters=None): + self.filters = frappe._dict(filters or {}) + self.entries = [] + self.doc_info = {} + self.party_details = {} - return columns, data + @classmethod + def execute(cls, filters=None): + return cls(filters).run() + def run(self): + self.validate_filters() + return self.get_columns(), self.get_data() -def validate_filters(filters): - """Validate report filters""" - filters = frappe._dict(filters or {}) + def validate_filters(self): + if not self.filters.from_date or not self.filters.to_date: + frappe.throw(_("From Date and To Date are required")) - if not filters.from_date or not filters.to_date: - frappe.throw(_("From Date and To Date are required")) + if self.filters.from_date > self.filters.to_date: + frappe.throw(_("From Date must be before To Date")) - if filters.from_date > filters.to_date: - frappe.throw(_("From Date must be before To Date")) + def get_data(self): + self.entries = self.get_entries_query().run(as_dict=True) + if not self.entries: + return [] + self.doc_info = self.fetch_additional_doc_info() + self.party_details = self.fetch_party_details() + return self.build_rows() -def get_tax_withholding_data(filters): - """Process entries into final report format""" - data = [] - entries = get_tax_withholding_entries(filters) - if not entries: - return data + def build_rows(self): + rows = [] + for entry in self.entries: + doc_details = ( + self.doc_info.get((entry.transaction_type, entry.ref_no), {}) if entry.ref_no else {} + ) + party_info = self.party_details.get((entry.party_type, entry.party), {}) + rows.append({**entry, **doc_details, **party_info}) - doc_info = get_additional_doc_info(entries) - party_details = get_party_details(entries) + rows.sort( + key=lambda x: ( + x["tax_withholding_category"] or "", + x["transaction_date"] or "", + x["withholding_name"] or "", + ) + ) + return rows - for entry in entries: - doc_details = frappe._dict() - if entry.taxable_name: - doc_details = doc_info.get((entry.taxable_doctype, entry.taxable_name), {}) + def get_entries_query(self): + twe = frappe.qb.DocType("Tax Withholding Entry") + query = ( + frappe.qb.from_(twe) + .select( + twe.party_type, + twe.party, + IfNull(twe.tax_id, "").as_("tax_id"), + twe.tax_withholding_category, + twe.taxable_amount.as_("total_amount"), + twe.tax_rate.as_("rate"), + twe.withholding_amount.as_("tax_amount"), + IfNull(twe.taxable_doctype, "").as_("transaction_type"), + IfNull(twe.taxable_name, "").as_("ref_no"), + twe.taxable_date, + IfNull(twe.withholding_doctype, "").as_("withholding_doctype"), + IfNull(twe.withholding_name, "").as_("withholding_name"), + twe.withholding_date.as_("transaction_date"), + ) + .where(twe.docstatus == 1) + .where(twe.withholding_date >= self.filters.from_date) + .where(twe.withholding_date <= self.filters.to_date) + .where(IfNull(twe.withholding_name, "") != "") + .where(twe.status != "Duplicate") + ) - party_info = party_details.get((entry.party_type, entry.party), {}) + if self.filters.company: + query = query.where(twe.company == self.filters.company) + if self.filters.party_type: + query = query.where(twe.party_type == self.filters.party_type) + if self.filters.party: + query = query.where(twe.party == self.filters.party) - row = { - "section_code": entry.tax_withholding_category, - "entity_type": party_info.get("entity_type"), - "rate": entry.tax_rate, - "total_amount": entry.taxable_amount, - "grand_total": doc_details.get("grand_total", 0), - "base_total": doc_details.get("base_total", 0), - "tax_amount": entry.withholding_amount, - "transaction_date": entry.withholding_date, - "transaction_type": entry.taxable_doctype, - "ref_no": entry.taxable_name, - "taxable_date": entry.taxable_date, - "supplier_invoice_no": doc_details.get("bill_no"), - "supplier_invoice_date": doc_details.get("bill_date"), - "withholding_doctype": entry.withholding_doctype, - "withholding_name": entry.withholding_name, - "party_name": party_info.get("party_name"), - "tax_id": entry.tax_id, - "party": entry.party, - "party_type": entry.party_type, - } - data.append(row) + return query - # Sort by section code, transaction date, then withholding_name for deterministic ordering - data.sort( - key=lambda x: (x["section_code"] or "", x["transaction_date"] or "", x["withholding_name"] or "") - ) - return data + def fetch_party_details(self): + parties_by_type = {pt: set() for pt in self.party_types} + for entry in self.entries: + if entry.party_type in parties_by_type and entry.party: + parties_by_type[entry.party_type].add(entry.party) + party_map = {} + for party_type, party_set in parties_by_type.items(): + if not party_set: + continue -def get_party_details(entries): - """Fetch party details in batch for all entries""" - party_map = frappe._dict() - parties_by_type = {"Customer": set(), "Supplier": set()} + query = self.get_party_query(party_type, party_set) + if query is None: + continue - # Group parties by type - for entry in entries: - if entry.party_type in parties_by_type and entry.party: - parties_by_type[entry.party_type].add(entry.party) + for row in query.run(as_dict=True): + party_map[(party_type, row.pop("name"))] = row - # Batch fetch for each party type - for party_type, party_set in parties_by_type.items(): - if not party_type or not party_set: - continue + return party_map + def get_party_query(self, party_type, party_set): doctype = frappe.qb.DocType(party_type) fields = [doctype.name] if party_type == "Supplier": - fields.extend([doctype.supplier_type.as_("entity_type"), doctype.supplier_name.as_("party_name")]) + fields.extend( + [ + doctype.supplier_type.as_("party_entity_type"), + doctype.supplier_name.as_("party_name"), + ] + ) elif party_type == "Customer": - fields.extend([doctype.customer_type.as_("entity_type"), doctype.customer_name.as_("party_name")]) + fields.extend( + [ + doctype.customer_type.as_("party_entity_type"), + doctype.customer_name.as_("party_name"), + ] + ) + else: + return None - query = frappe.qb.from_(doctype).select(*fields).where(doctype.name.isin(party_set)) - party_details = query.run(as_dict=True) + return frappe.qb.from_(doctype).select(*fields).where(doctype.name.isin(party_set)) - for party in party_details: - party_map[(party_type, party.name)] = party + def fetch_additional_doc_info(self): + docs_by_type = {dt: set() for dt in self.document_types} + for entry in self.entries: + if entry.ref_no and entry.transaction_type in docs_by_type: + docs_by_type[entry.transaction_type].add(entry.ref_no) - return party_map + doc_info = {} + for doctype_name, voucher_set in docs_by_type.items(): + if not voucher_set: + continue + + query = self.get_doc_info_query(doctype_name, voucher_set) + if query is None: + continue + + for row in query.run(as_dict=True): + doc_info[(doctype_name, row.pop("name"))] = row + + return doc_info + + def get_doc_info_query(self, doctype_name, voucher_set): + if doctype_name == "Purchase Invoice": + get_doc_fields = self.get_purchase_invoice_fields + elif doctype_name == "Sales Invoice": + get_doc_fields = self.get_sales_invoice_fields + elif doctype_name == "Payment Entry": + get_doc_fields = self.get_payment_entry_fields + elif doctype_name == "Journal Entry": + get_doc_fields = self.get_journal_entry_fields + else: + return None + + doctype = frappe.qb.DocType(doctype_name) + fields = [doctype.name, *get_doc_fields(doctype)] + return frappe.qb.from_(doctype).select(*fields).where(doctype.name.isin(voucher_set)) + + def get_purchase_invoice_fields(self, doctype): + return [ + doctype.grand_total, + doctype.base_total, + doctype.bill_no.as_("supplier_invoice_no"), + doctype.bill_date.as_("supplier_invoice_date"), + ] + + def get_sales_invoice_fields(self, doctype): + return [doctype.grand_total, doctype.base_total] + + def get_payment_entry_fields(self, doctype): + return [ + doctype.paid_amount_after_tax.as_("grand_total"), + doctype.base_paid_amount.as_("base_total"), + ] + + def get_journal_entry_fields(self, doctype): + return [doctype.total_debit.as_("grand_total"), doctype.total_debit.as_("base_total")] + + def get_columns(self): + party_type = self.filters.get("party_type", "Party") + return [ + { + "label": _("Tax Withholding Category"), + "options": "Tax Withholding Category", + "fieldname": "tax_withholding_category", + "fieldtype": "Link", + "width": 90, + }, + {"label": _("Tax Id"), "fieldname": "tax_id", "fieldtype": "Data", "width": 60}, + { + "label": _(f"{party_type} Name"), + "fieldname": "party_name", + "fieldtype": "Data", + "width": 180, + }, + { + "label": _(party_type), + "fieldname": "party", + "fieldtype": "Dynamic Link", + "options": "party_type", + "width": 180, + }, + { + "label": _(f"{party_type} Type"), + "fieldname": "party_entity_type", + "fieldtype": "Data", + "width": 100, + }, + { + "label": _("Supplier Invoice No"), + "fieldname": "supplier_invoice_no", + "fieldtype": "Data", + "width": 120, + }, + { + "label": _("Supplier Invoice Date"), + "fieldname": "supplier_invoice_date", + "fieldtype": "Date", + "width": 120, + }, + {"label": _("Tax Rate %"), "fieldname": "rate", "fieldtype": "Percent", "width": 60}, + { + "label": _("Taxable Amount"), + "fieldname": "total_amount", + "fieldtype": "Currency", + "width": 120, + }, + {"label": _("Tax Amount"), "fieldname": "tax_amount", "fieldtype": "Currency", "width": 120}, + { + "label": _("Grand Total (Company Currency)"), + "fieldname": "base_total", + "fieldtype": "Currency", + "width": 150, + }, + { + "label": _("Grand Total (Transaction Currency)"), + "fieldname": "grand_total", + "fieldtype": "Currency", + "width": 170, + }, + {"label": _("Reference Date"), "fieldname": "taxable_date", "fieldtype": "Date", "width": 100}, + { + "label": _("Transaction Type"), + "fieldname": "transaction_type", + "fieldtype": "Data", + "width": 130, + }, + { + "label": _("Reference No."), + "fieldname": "ref_no", + "fieldtype": "Dynamic Link", + "options": "transaction_type", + "width": 180, + }, + { + "label": _("Date of Transaction"), + "fieldname": "transaction_date", + "fieldtype": "Date", + "width": 100, + }, + { + "label": _("Withholding Document"), + "fieldname": "withholding_name", + "fieldtype": "Dynamic Link", + "options": "withholding_doctype", + "width": 150, + }, + ] -def get_columns(filters): - """Generate report columns based on filters""" - columns = [ - { - "label": _("Section Code"), - "options": "Tax Withholding Category", - "fieldname": "section_code", - "fieldtype": "Link", - "width": 90, - }, - {"label": _("Tax Id"), "fieldname": "tax_id", "fieldtype": "Data", "width": 60}, - { - "label": _(f"{filters.get('party_type', 'Party')} Name"), - "fieldname": "party_name", - "fieldtype": "Data", - "width": 180, - }, - { - "label": _(filters.get("party_type", "Party")), - "fieldname": "party", - "fieldtype": "Dynamic Link", - "options": "party_type", - "width": 180, - }, - { - "label": _("Entity Type"), - "fieldname": "entity_type", - "fieldtype": "Data", - "width": 100, - }, - { - "label": _("Supplier Invoice No"), - "fieldname": "supplier_invoice_no", - "fieldtype": "Data", - "width": 120, - }, - { - "label": _("Supplier Invoice Date"), - "fieldname": "supplier_invoice_date", - "fieldtype": "Date", - "width": 120, - }, - { - "label": _("Tax Rate %"), - "fieldname": "rate", - "fieldtype": "Percent", - "width": 60, - }, - { - "label": _("Taxable Amount"), - "fieldname": "total_amount", - "fieldtype": "Currency", - "width": 120, - }, - { - "label": _("Tax Amount"), - "fieldname": "tax_amount", - "fieldtype": "Currency", - "width": 120, - }, - { - "label": _("Grand Total (Company Currency)"), - "fieldname": "base_total", - "fieldtype": "Currency", - "width": 150, - }, - { - "label": _("Grand Total (Transaction Currency)"), - "fieldname": "grand_total", - "fieldtype": "Currency", - "width": 170, - }, - { - "label": _("Reference Date"), - "fieldname": "taxable_date", - "fieldtype": "Date", - "width": 100, - }, - { - "label": _("Transaction Type"), - "fieldname": "transaction_type", - "fieldtype": "Data", - "width": 130, - }, - { - "label": _("Reference No."), - "fieldname": "ref_no", - "fieldtype": "Dynamic Link", - "options": "transaction_type", - "width": 180, - }, - { - "label": _("Date of Transaction"), - "fieldname": "transaction_date", - "fieldtype": "Date", - "width": 100, - }, - { - "label": _("Withholding Document"), - "fieldname": "withholding_name", - "fieldtype": "Dynamic Link", - "options": "withholding_doctype", - "width": 150, - }, - ] - - return columns - - -def get_tax_withholding_entries(filters): - twe = frappe.qb.DocType("Tax Withholding Entry") - query = ( - frappe.qb.from_(twe) - .select( - twe.company, - twe.party_type, - twe.party, - IfNull(twe.tax_id, "").as_("tax_id"), - twe.tax_withholding_category, - IfNull(twe.tax_withholding_group, "").as_("tax_withholding_group"), - twe.taxable_amount, - twe.tax_rate, - twe.withholding_amount, - IfNull(twe.taxable_doctype, "").as_("taxable_doctype"), - IfNull(twe.taxable_name, "").as_("taxable_name"), - twe.taxable_date, - IfNull(twe.under_withheld_reason, "").as_("under_withheld_reason"), - IfNull(twe.lower_deduction_certificate, "").as_("lower_deduction_certificate"), - IfNull(twe.withholding_doctype, "").as_("withholding_doctype"), - IfNull(twe.withholding_name, "").as_("withholding_name"), - twe.withholding_date, - twe.status, - ) - .where(twe.docstatus == 1) - .where(twe.withholding_date >= filters.from_date) - .where(twe.withholding_date <= filters.to_date) - .where(IfNull(twe.withholding_name, "") != "") - .where(twe.status != "Duplicate") - ) - - if filters.get("company"): - query = query.where(twe.company == filters.get("company")) - - if filters.get("party_type"): - query = query.where(twe.party_type == filters.get("party_type")) - - if filters.get("party"): - query = query.where(twe.party == filters.get("party")) - - return query.run(as_dict=True) - - -def get_additional_doc_info(entries): - """Fetch additional document information in batch""" - doc_info = {} - docs_by_type = { - "Purchase Invoice": set(), - "Sales Invoice": set(), - "Payment Entry": set(), - "Journal Entry": set(), - } - - # Group documents by type - for entry in entries: - if entry.taxable_name and entry.taxable_doctype in docs_by_type: - docs_by_type[entry.taxable_doctype].add(entry.taxable_name) - - for doctype_name, voucher_set in docs_by_type.items(): - if voucher_set: - _fetch_doc_info(doctype_name, voucher_set, doc_info) - - return doc_info - - -def _fetch_doc_info(doctype_name, voucher_set, doc_info): - doctype = frappe.qb.DocType(doctype_name) - fields = [doctype.name] - - # Add doctype-specific fields - if doctype_name == "Purchase Invoice": - fields.extend([doctype.grand_total, doctype.base_total, doctype.bill_no, doctype.bill_date]) - elif doctype_name == "Sales Invoice": - fields.extend([doctype.grand_total, doctype.base_total]) - elif doctype_name == "Payment Entry": - fields.extend( - [doctype.paid_amount_after_tax.as_("grand_total"), doctype.base_paid_amount.as_("base_total")] - ) - elif doctype_name == "Journal Entry": - fields.extend([doctype.total_debit.as_("grand_total"), doctype.total_debit.as_("base_total")]) - else: - return - - query = frappe.qb.from_(doctype).select(*fields).where(doctype.name.isin(voucher_set)) - entries = query.run(as_dict=True) - - for entry in entries: - doc_info[(doctype_name, entry.name)] = entry +execute = TaxWithholdingDetailsReport.execute 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 91683867188..de03aaef77e 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 @@ -40,7 +40,7 @@ class TestTaxWithholdingDetails(ERPNextTestSuite, AccountsTestMixin): expected_values = [ [jv.name, "TCS", 0.075, 1000.75, 0.75, 1000.75], - ["", "TCS", 0.075, 0, 0.75, 0], + ["", "TCS", 0.075, None, 0.75, None], [si.name, "TCS", 0.075, 1000.0, 0.75, 1000.75], ] self.check_expected_values(result, expected_values) @@ -124,7 +124,7 @@ class TestTaxWithholdingDetails(ERPNextTestSuite, AccountsTestMixin): voucher_expected_values = expected_values[i] voucher_actual_values = ( voucher.ref_no, - voucher.section_code, + voucher.tax_withholding_category, voucher.rate, voucher.base_total, voucher.tax_amount, 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 59296602b3d..3ab3986b013 100644 --- a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py +++ b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py @@ -2,121 +2,94 @@ import frappe from frappe import _ from erpnext.accounts.report.tax_withholding_details.tax_withholding_details import ( - get_tax_withholding_data, + TaxWithholdingDetailsReport, ) from erpnext.accounts.utils import get_fiscal_year -def execute(filters=None): - validate_filters(filters) +class TDSComputationSummaryReport(TaxWithholdingDetailsReport): + GROUP_BY_FIELDS = ("party_type", "party", "tax_withholding_category") + CARRY_OVER_FIELDS = ( + "tax_id", + "party", + "party_type", + "party_name", + "tax_withholding_category", + "party_entity_type", + "rate", + ) + AGGREGATE_FIELDS = ("total_amount", "tax_amount") - data = get_tax_withholding_data(filters) - columns = get_columns(filters) + def validate_filters(self): + if self.filters.from_date > self.filters.to_date: + frappe.throw(_("From Date must be before To Date")) - final_result = group_by_party_and_category(data, filters) + from_year = get_fiscal_year(self.filters.from_date)[0] + to_year = get_fiscal_year(self.filters.to_date)[0] + if from_year != to_year: + frappe.throw(_("From Date and To Date lie in different Fiscal Year")) - return columns, final_result + self.filters.fiscal_year = from_year + def get_data(self): + return self.group_rows(super().get_data()) -def validate_filters(filters): - """Validate if dates are properly set and lie in the same fiscal year""" - if filters.from_date > filters.to_date: - frappe.throw(_("From Date must be before To Date")) + def group_rows(self, data): + grouped = {} + for row in data: + key = tuple(row.get(f) for f in self.GROUP_BY_FIELDS) + bucket = grouped.setdefault( + key, + { + **{f: row.get(f) for f in self.CARRY_OVER_FIELDS}, + **{f: 0.0 for f in self.AGGREGATE_FIELDS}, + }, + ) - from_year = get_fiscal_year(filters.from_date)[0] - to_year = get_fiscal_year(filters.to_date)[0] - if from_year != to_year: - frappe.throw(_("From Date and To Date lie in different Fiscal Year")) + for f in self.AGGREGATE_FIELDS: + bucket[f] += row.get(f) or 0.0 - filters["fiscal_year"] = from_year + return list(grouped.values()) - -def group_by_party_and_category(data, filters): - party_category_wise_map = {} - - for row in data: - party_category_wise_map.setdefault( - (row.get("party"), row.get("section_code")), + def get_columns(self): + party_type = self.filters.get("party_type", "Party") + return [ + {"label": _("Tax Id"), "fieldname": "tax_id", "fieldtype": "Data", "width": 90}, { - "tax_id": row.get("tax_id"), - "party": row.get("party"), - "party_name": row.get("party_name"), - "section_code": row.get("section_code"), - "entity_type": row.get("entity_type"), - "rate": row.get("rate"), - "total_amount": 0.0, - "tax_amount": 0.0, + "label": _(party_type), + "fieldname": "party", + "fieldtype": "Dynamic Link", + "options": "party_type", + "width": 180, }, - ) - - 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 - ) - - final_result = get_final_result(party_category_wise_map) - - return final_result + { + "label": _(f"{party_type} Name"), + "fieldname": "party_name", + "fieldtype": "Data", + "width": 180, + }, + { + "label": _("Tax Withholding Category"), + "options": "Tax Withholding Category", + "fieldname": "tax_withholding_category", + "fieldtype": "Link", + "width": 180, + }, + { + "label": _(f"{party_type} Type"), + "fieldname": "party_entity_type", + "fieldtype": "Data", + "width": 180, + }, + {"label": _("Tax Rate %"), "fieldname": "rate", "fieldtype": "Percent", "width": 120}, + { + "label": _("Total Taxable Amount"), + "fieldname": "total_amount", + "fieldtype": "Float", + "width": 120, + }, + {"label": _("Tax Amount"), "fieldname": "tax_amount", "fieldtype": "Float", "width": 120}, + ] -def get_final_result(party_category_wise_map): - out = [] - for _key, value in party_category_wise_map.items(): - out.append(value) - - return out - - -def get_columns(filters): - columns = [ - {"label": _("Tax Id"), "fieldname": "tax_id", "fieldtype": "Data", "width": 90}, - { - "label": _(filters.get("party_type")), - "fieldname": "party", - "fieldtype": "Dynamic Link", - "options": "party_type", - "width": 180, - }, - { - "label": _(f"{filters.get('party_type', 'Party')} Name"), - "fieldname": "party_name", - "fieldtype": "Data", - "width": 180, - }, - { - "label": _("Section Code"), - "options": "Tax Withholding Category", - "fieldname": "section_code", - "fieldtype": "Link", - "width": 180, - }, - { - "label": _("Entity Type"), - "fieldname": "entity_type", - "fieldtype": "Data", - "width": 180, - }, - { - "label": _("Tax Rate %"), - "fieldname": "rate", - "fieldtype": "Percent", - "width": 120, - }, - { - "label": _("Total Taxable Amount"), - "fieldname": "total_amount", - "fieldtype": "Float", - "width": 120, - }, - { - "label": _("Tax Amount"), - "fieldname": "tax_amount", - "fieldtype": "Float", - "width": 120, - }, - ] - - return columns +execute = TDSComputationSummaryReport.execute