From 50ce61ae02a5fb53c52d1a29c395cc8524c32c10 Mon Sep 17 00:00:00 2001 From: ljain112 Date: Wed, 31 Dec 2025 14:26:22 +0530 Subject: [PATCH 1/5] fix(tds): correct tax logic for customer (cherry picked from commit 86b0f67dbc9adc1352379d2660ffe67366a13517) --- .../test_tax_withholding_category.py | 7 +------ .../tax_withholding_entry/tax_withholding_entry.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py index 782f5a06cfb..a9773ceae60 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py @@ -415,7 +415,6 @@ class TestTaxWithholdingCategory(IntegrationTestCase): "cost_center": "Main - _TC", "tax_amount": 500, "description": "Test", - "add_deduct_tax": "Add", }, ) pi.save() @@ -506,7 +505,6 @@ class TestTaxWithholdingCategory(IntegrationTestCase): "cost_center": "Main - _TC", "tax_amount": 200, "description": "Test Gross Tax", - "add_deduct_tax": "Add", }, ) si.save() @@ -541,10 +539,10 @@ class TestTaxWithholdingCategory(IntegrationTestCase): "cost_center": "Main - _TC", "tax_amount": 400, "description": "Test Gross Tax", - "add_deduct_tax": "Add", }, ) si.save() + si.reload() si.submit() invoices.append(si) # For amount before threshold (first 8000 + VAT): TCS entry with amount zero @@ -594,7 +592,6 @@ class TestTaxWithholdingCategory(IntegrationTestCase): "cost_center": "Main - _TC", "tax_amount": 500, "description": "VAT added to test TDS calculation on gross amount", - "add_deduct_tax": "Add", }, ) si.save() @@ -1024,7 +1021,6 @@ class TestTaxWithholdingCategory(IntegrationTestCase): "cost_center": "Main - _TC", "tax_amount": 1000, "description": "VAT added to test TDS calculation on gross amount", - "add_deduct_tax": "Add", }, ) pi.save() @@ -1162,7 +1158,6 @@ class TestTaxWithholdingCategory(IntegrationTestCase): "cost_center": "Main - _TC", "tax_amount": 8000, "description": "Test", - "add_deduct_tax": "Add", }, ) diff --git a/erpnext/accounts/doctype/tax_withholding_entry/tax_withholding_entry.py b/erpnext/accounts/doctype/tax_withholding_entry/tax_withholding_entry.py index 4abbd2c28e4..6aff1116935 100644 --- a/erpnext/accounts/doctype/tax_withholding_entry/tax_withholding_entry.py +++ b/erpnext/accounts/doctype/tax_withholding_entry/tax_withholding_entry.py @@ -708,6 +708,10 @@ class TaxWithholdingController: existing_taxes = {row.account_head: row for row in self.doc.taxes if row.is_tax_withholding_account} precision = self.doc.precision("tax_amount", "taxes") conversion_rate = self.get_conversion_rate() + add_deduct_tax = "Deduct" + + if self.party_type == "Customer": + add_deduct_tax = "Add" for account_head, base_amount in account_amount_map.items(): tax_amount = flt(base_amount / conversion_rate, precision) @@ -724,6 +728,7 @@ class TaxWithholdingController: tax_row = self._create_tax_row(account_head, tax_amount) for_update = False + tax_row.add_deduct_tax = add_deduct_tax # Set item-wise tax breakup for this tax row self._set_item_wise_tax_for_tds( tax_row, account_head, category_withholding_map, for_update=for_update @@ -743,7 +748,6 @@ class TaxWithholdingController: "account_head": account_head, "description": account_head, "cost_center": cost_center, - "add_deduct_tax": "Deduct", "tax_amount": tax_amount, "dont_recompute_tax": 1, }, @@ -807,12 +811,14 @@ class TaxWithholdingController: else: item_tax_amount = 0 + multiplier = -1 if tax_row.add_deduct_tax == "Deduct" else 1 + self.doc._item_wise_tax_details.append( frappe._dict( item=item, tax=tax_row, rate=category.tax_rate, - amount=item_tax_amount * -1, # Negative because it's a deduction + amount=item_tax_amount * multiplier, taxable_amount=item_base_taxable, ) ) From fc517f7fa28d754be2ffce541bcd1b784209fcee Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Tue, 13 Jan 2026 15:11:37 +0530 Subject: [PATCH 2/5] Merge pull request #51707 from mihir-kandoi/ci-patch-test-2 --- .github/workflows/patch.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/patch.yml b/.github/workflows/patch.yml index fac11c071db..65223cb1960 100644 --- a/.github/workflows/patch.yml +++ b/.github/workflows/patch.yml @@ -113,8 +113,8 @@ jobs: jq 'del(.install_apps)' ~/frappe-bench/sites/test_site/site_config.json > tmp.json mv tmp.json ~/frappe-bench/sites/test_site/site_config.json - wget https://erpnext.com/files/v13-erpnext.sql.gz - bench --site test_site --force restore ~/frappe-bench/v13-erpnext.sql.gz + wget https://frappe.io/files/erpnext-v14.sql.gz + bench --site test_site --force restore ~/frappe-bench/erpnext-v14.sql.gz git -C "apps/frappe" remote set-url upstream https://github.com/frappe/frappe.git git -C "apps/erpnext" remote set-url upstream https://github.com/frappe/erpnext.git @@ -142,7 +142,6 @@ jobs: bench --site test_site migrate } - update_to_version 14 3.11 update_to_version 15 3.13 echo "Updating to latest version" From 0363b01ab74d47cc0be0ae0146df7ab9054e2be0 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 12 Jan 2026 19:20:27 +0530 Subject: [PATCH 3/5] fix: Redirect to Desktop after signup (#51696) (cherry picked from commit 3bc58fb46fd7490134f87e32bf2b44d2ad0a4703) --- erpnext/hooks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 9d7b7a5ed70..3b0f338cf84 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -8,7 +8,7 @@ app_email = "hello@frappe.io" app_license = "GNU General Public License (v3)" source_link = "https://github.com/frappe/erpnext" app_logo_url = "/assets/erpnext/images/erpnext-logo.svg" -app_home = "/app/home" +app_home = "/desk" add_to_apps_screen = [ { From 4b85d51257f6f1b6e7311bab1505805cac3d7389 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:05:14 +0530 Subject: [PATCH 4/5] fix(asset value adjustment): skip cancelling revaluation journal entry if already cancelled (backport #51666) (#51716) Co-authored-by: Navin-S-R --- .../doctype/journal_entry/journal_entry.py | 28 +++++++++++++++---- .../asset_value_adjustment.py | 13 ++++++++- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 93b95d7c02e..ce435482ae5 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -184,6 +184,9 @@ class JournalEntry(AccountsController): else: return self._submit() + def before_cancel(self): + self.has_asset_adjustment_entry() + def cancel(self): if len(self.accounts) > 100: queue_submission(self, "_cancel") @@ -554,12 +557,27 @@ class JournalEntry(AccountsController): ) frappe.db.set_value("Journal Entry", self.name, "inter_company_journal_entry_reference", "") - def unlink_asset_adjustment_entry(self): - frappe.db.sql( - """ update `tabAsset Value Adjustment` - set journal_entry = null where journal_entry = %s""", - self.name, + def has_asset_adjustment_entry(self): + if self.flags.get("via_asset_value_adjustment"): + return + + asset_value_adjustment = frappe.db.get_value( + "Asset Value Adjustment", {"docstatus": 1, "journal_entry": self.name}, "name" ) + if asset_value_adjustment: + frappe.throw( + _( + "Cannot cancel this document as it is linked with the submitted Asset Value Adjustment {0}. Please cancel the Asset Value Adjustment to continue." + ).format(frappe.utils.get_link_to_form("Asset Value Adjustment", asset_value_adjustment)) + ) + + def unlink_asset_adjustment_entry(self): + AssetValueAdjustment = frappe.qb.DocType("Asset Value Adjustment") + ( + frappe.qb.update(AssetValueAdjustment) + .set(AssetValueAdjustment.journal_entry, None) + .where(AssetValueAdjustment.journal_entry == self.name) + ).run() def validate_party(self): for d in self.get("accounts"): diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py index 982c6f4fc7d..c033cda05b5 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -74,7 +74,7 @@ class AssetValueAdjustment(Document): ) def on_cancel(self): - frappe.get_doc("Journal Entry", self.journal_entry).cancel() + self.cancel_asset_revaluation_entry() self.update_asset() add_asset_activity( self.asset, @@ -167,6 +167,17 @@ class AssetValueAdjustment(Document): if dimension.get("mandatory_for_pl"): debit_entry.update({dimension["fieldname"]: dimension_value}) + def cancel_asset_revaluation_entry(self): + if not self.journal_entry: + return + + revaluation_entry = frappe.get_doc("Journal Entry", self.journal_entry) + if revaluation_entry.docstatus == 1: + # Ignore permissions to match Journal Entry submission behavior + revaluation_entry.flags.ignore_permissions = True + revaluation_entry.flags.via_asset_value_adjustment = True + revaluation_entry.cancel() + def update_asset(self): asset = self.update_asset_value_after_depreciation() note = self.get_adjustment_note() From 3420e21d456e7602f06635b311ce9b31fb2b8c02 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 13 Jan 2026 17:02:39 +0530 Subject: [PATCH 5/5] fix: stock module not opened when no warehouses (cherry picked from commit 9de3b0722390beb73067f1c594c8f2f3ec0369ab) --- .../stock_value_by_item_group/stock_value_by_item_group.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/dashboard_chart_source/stock_value_by_item_group/stock_value_by_item_group.py b/erpnext/stock/dashboard_chart_source/stock_value_by_item_group/stock_value_by_item_group.py index 68f64619e7b..e2d0b1e41e8 100644 --- a/erpnext/stock/dashboard_chart_source/stock_value_by_item_group/stock_value_by_item_group.py +++ b/erpnext/stock/dashboard_chart_source/stock_value_by_item_group/stock_value_by_item_group.py @@ -53,12 +53,14 @@ def get_stock_value_by_item_group(company): .inner_join(item_doctype) .on(doctype.item_code == item_doctype.name) .select(item_doctype.item_group, stock_value.as_("stock_value")) - .where(doctype.warehouse.isin(warehouses)) .groupby(item_doctype.item_group) .orderby(stock_value, order=frappe.qb.desc) .limit(10) ) + if warehouses: + query = query.where(doctype.warehouse.isin(warehouses)) + results = query.run(as_dict=True) labels = []