From 44620884c1ca89bf62798b15148a75834278e489 Mon Sep 17 00:00:00 2001 From: Sudharsanan11 Date: Wed, 18 Feb 2026 23:59:42 +0530 Subject: [PATCH 1/4] fix(stock): validate company for receipt documents and expense accounts (cherry picked from commit 15dfc08a3181063f18147af0ad6170393531cfae) --- .../landed_cost_voucher.py | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py index a70af1fc384..4dfcb212392 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -66,6 +66,7 @@ class LandedCostVoucher(Document): self.check_mandatory() self.validate_receipt_documents() self.validate_line_items() + self.validate_expense_accounts() init_landed_taxes_and_totals(self) self.set_total_taxes_and_charges() if not self.get("items"): @@ -101,11 +102,27 @@ class LandedCostVoucher(Document): receipt_documents = [] for d in self.get("purchase_receipts"): - docstatus = frappe.db.get_value(d.receipt_document_type, d.receipt_document, "docstatus") + docstatus, company = frappe.get_cached_value( + d.receipt_document_type, d.receipt_document, ["docstatus", "company"] + ) if docstatus != 1: msg = f"Row {d.idx}: {d.receipt_document_type} {frappe.bold(d.receipt_document)} must be submitted" frappe.throw(_(msg), title=_("Invalid Document")) + if company != self.company: + frappe.throw( + _( + "Row {0}: {1} {2} is linked to company {3}. Please select a document belonging to company {4}." + ).format( + d.idx, + d.receipt_document_type, + frappe.bold(d.receipt_document), + frappe.bold(company), + frappe.bold(self.company), + ), + title=_("Incorrect Company"), + ) + if d.receipt_document_type == "Purchase Invoice": update_stock = frappe.db.get_value( d.receipt_document_type, d.receipt_document, "update_stock" @@ -137,6 +154,23 @@ class LandedCostVoucher(Document): _("Row {0}: Cost center is required for an item {1}").format(item.idx, item.item_code) ) + def validate_expense_accounts(self): + for t in self.taxes: + company = frappe.get_cached_value("Account", t.expense_account, "company") + + if company != self.company: + frappe.throw( + _( + "Row {0}: Expense Account {1} is linked to company {2}. Please select an account belonging to company {3}." + ).format( + t.idx, + frappe.bold(t.expense_account), + frappe.bold(company), + frappe.bold(self.company), + ), + title=_("Incorrect Account"), + ) + def set_total_taxes_and_charges(self): self.total_taxes_and_charges = sum(flt(d.base_amount) for d in self.get("taxes")) From 74e71f386807bc87a92a5c9176cdd5925198749d Mon Sep 17 00:00:00 2001 From: Sudharsanan11 Date: Fri, 20 Feb 2026 12:15:40 +0530 Subject: [PATCH 2/4] fix: set company based expense account (cherry picked from commit d54d0c25a23ac65c6fe1fd971bdcc0c1cab5ca1a) # Conflicts: # erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py --- .../test_landed_cost_voucher.py | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py index 39f9ecb915d..a9b36f8661f 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py @@ -1076,6 +1076,7 @@ def make_landed_cost_voucher(**args): lcv = frappe.new_doc("Landed Cost Voucher") lcv.company = args.company or "_Test Company" lcv.distribute_charges_based_on = args.distribute_charges_based_on or "Amount" + expense_account = get_expense_account(args.company or "_Test Company") lcv.set( "purchase_receipts", @@ -1090,6 +1091,7 @@ def make_landed_cost_voucher(**args): ], ) +<<<<<<< HEAD lcv.set( "taxes", [ @@ -1100,6 +1102,19 @@ def make_landed_cost_voucher(**args): } ], ) +======= + if args.charges: + lcv.set( + "taxes", + [ + { + "description": "Shipping Charges", + "expense_account": args.expense_account or expense_account, + "amount": args.charges, + } + ], + ) +>>>>>>> d54d0c25a2 (fix: set company based expense account) if not args.do_not_save: lcv.insert() @@ -1115,6 +1130,7 @@ def create_landed_cost_voucher(receipt_document_type, receipt_document, company, lcv = frappe.new_doc("Landed Cost Voucher") lcv.company = company lcv.distribute_charges_based_on = "Amount" + expense_account = get_expense_account(company) lcv.set( "purchase_receipts", @@ -1134,7 +1150,7 @@ def create_landed_cost_voucher(receipt_document_type, receipt_document, company, [ { "description": "Insurance Charges", - "expense_account": "Expenses Included In Valuation - TCP1", + "expense_account": expense_account, "amount": charges, } ], @@ -1149,6 +1165,11 @@ def create_landed_cost_voucher(receipt_document_type, receipt_document, company, return lcv +def get_expense_account(company): + company_abbr = frappe.get_cached_value("Company", company, "abbr") + return f"Expenses Included In Valuation - {company_abbr}" + + def distribute_landed_cost_on_items(lcv): based_on = lcv.distribute_charges_based_on.lower() total = sum(flt(d.get(based_on)) for d in lcv.get("items")) From 9b0d4ab4daa8ff3aac0c57a7e26ea4e80aca035a Mon Sep 17 00:00:00 2001 From: Sudharsanan11 Date: Mon, 23 Feb 2026 01:59:25 +0530 Subject: [PATCH 3/4] test(stock): add test to validate company for receipts and expense accounts (cherry picked from commit d58171987c4a63de234acfd2c1f2cd53c767ad03) --- .../landed_cost_voucher.py | 6 ++++ .../test_landed_cost_voucher.py | 33 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py index 4dfcb212392..9a478ace4d3 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -14,6 +14,10 @@ from erpnext.controllers.taxes_and_totals import init_landed_taxes_and_totals from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos +class IncorrectCompanyValidationError(frappe.ValidationError): + pass + + class LandedCostVoucher(Document): # begin: auto-generated types # This code is auto-generated. Do not modify anything in this block. @@ -121,6 +125,7 @@ class LandedCostVoucher(Document): frappe.bold(self.company), ), title=_("Incorrect Company"), + exc=IncorrectCompanyValidationError, ) if d.receipt_document_type == "Purchase Invoice": @@ -169,6 +174,7 @@ class LandedCostVoucher(Document): frappe.bold(self.company), ), title=_("Incorrect Account"), + exc=IncorrectCompanyValidationError, ) def set_total_taxes_and_charges(self): diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py index a9b36f8661f..a81f92dd369 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py @@ -174,6 +174,39 @@ class TestLandedCostVoucher(FrappeTestCase): self.assertEqual(last_sle.qty_after_transaction, last_sle_after_landed_cost.qty_after_transaction) self.assertEqual(last_sle_after_landed_cost.stock_value - last_sle.stock_value, 50.0) + def test_lcv_validates_company(self): + from erpnext.stock.doctype.landed_cost_voucher.landed_cost_voucher import ( + IncorrectCompanyValidationError, + ) + + company_a = "_Test Company" + company_b = "_Test Company with perpetual inventory" + + pr = make_purchase_receipt( + company=company_a, + warehouse="Stores - _TC", + qty=1, + rate=100, + ) + + lcv = make_landed_cost_voucher( + company=company_b, + receipt_document_type="Purchase Receipt", + receipt_document=pr.name, + charges=50, + do_not_save=True, + ) + + self.assertRaises(IncorrectCompanyValidationError, lcv.validate_receipt_documents) + lcv.company = company_a + + self.assertRaises(IncorrectCompanyValidationError, lcv.validate_expense_accounts) + lcv.taxes[0].expense_account = get_expense_account(company_a) + + lcv.save() + distribute_landed_cost_on_items(lcv) + lcv.submit() + def test_landed_cost_voucher_for_zero_purchase_rate(self): "Test impact of LCV on future stock balances." from erpnext.stock.doctype.item.test_item import make_item From 6846f02cea8bc2bbf12dcd36d3f946e45de87fd7 Mon Sep 17 00:00:00 2001 From: Kavin <78342682+kavin-114@users.noreply.github.com> Date: Tue, 3 Mar 2026 21:28:34 +0530 Subject: [PATCH 4/4] fix: resolve conflicts --- .../landed_cost_voucher/test_landed_cost_voucher.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py index a81f92dd369..737df053832 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py @@ -1124,18 +1124,6 @@ def make_landed_cost_voucher(**args): ], ) -<<<<<<< HEAD - lcv.set( - "taxes", - [ - { - "description": "Shipping Charges", - "expense_account": args.expense_account or "Expenses Included In Valuation - TCP1", - "amount": args.charges, - } - ], - ) -======= if args.charges: lcv.set( "taxes", @@ -1147,7 +1135,6 @@ def make_landed_cost_voucher(**args): } ], ) ->>>>>>> d54d0c25a2 (fix: set company based expense account) if not args.do_not_save: lcv.insert()