Skip to content

Commit 282d8b1

Browse files
authored
Merge pull request #53138 from frappe/mergify/bp/version-16-hotfix/pr-52784
fix(stock): validate company for receipt documents and expense accounts (backport #52784)
2 parents 6eed4df + 4350c6b commit 282d8b1

2 files changed

Lines changed: 83 additions & 3 deletions

File tree

erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
1515

1616

17+
class IncorrectCompanyValidationError(frappe.ValidationError):
18+
pass
19+
20+
1721
class LandedCostVoucher(Document):
1822
# begin: auto-generated types
1923
# This code is auto-generated. Do not modify anything in this block.
@@ -75,6 +79,7 @@ def validate(self):
7579
self.check_mandatory()
7680
self.validate_receipt_documents()
7781
self.validate_line_items()
82+
self.validate_expense_accounts()
7883
init_landed_taxes_and_totals(self)
7984
self.set_total_taxes_and_charges()
8085
if not self.get("items"):
@@ -116,11 +121,28 @@ def validate_receipt_documents(self):
116121
receipt_documents = []
117122

118123
for d in self.get("purchase_receipts"):
119-
docstatus = frappe.db.get_value(d.receipt_document_type, d.receipt_document, "docstatus")
124+
docstatus, company = frappe.get_cached_value(
125+
d.receipt_document_type, d.receipt_document, ["docstatus", "company"]
126+
)
120127
if docstatus != 1:
121128
msg = f"Row {d.idx}: {d.receipt_document_type} {frappe.bold(d.receipt_document)} must be submitted"
122129
frappe.throw(_(msg), title=_("Invalid Document"))
123130

131+
if company != self.company:
132+
frappe.throw(
133+
_(
134+
"Row {0}: {1} {2} is linked to company {3}. Please select a document belonging to company {4}."
135+
).format(
136+
d.idx,
137+
d.receipt_document_type,
138+
frappe.bold(d.receipt_document),
139+
frappe.bold(company),
140+
frappe.bold(self.company),
141+
),
142+
title=_("Incorrect Company"),
143+
exc=IncorrectCompanyValidationError,
144+
)
145+
124146
if d.receipt_document_type == "Purchase Invoice":
125147
update_stock = frappe.db.get_value(
126148
d.receipt_document_type, d.receipt_document, "update_stock"
@@ -152,6 +174,24 @@ def validate_receipt_documents(self):
152174
_("Row {0}: Cost center is required for an item {1}").format(item.idx, item.item_code)
153175
)
154176

177+
def validate_expense_accounts(self):
178+
for t in self.taxes:
179+
company = frappe.get_cached_value("Account", t.expense_account, "company")
180+
181+
if company != self.company:
182+
frappe.throw(
183+
_(
184+
"Row {0}: Expense Account {1} is linked to company {2}. Please select an account belonging to company {3}."
185+
).format(
186+
t.idx,
187+
frappe.bold(t.expense_account),
188+
frappe.bold(company),
189+
frappe.bold(self.company),
190+
),
191+
title=_("Incorrect Account"),
192+
exc=IncorrectCompanyValidationError,
193+
)
194+
155195
def set_total_taxes_and_charges(self):
156196
self.total_taxes_and_charges = sum(flt(d.base_amount) for d in self.get("taxes"))
157197

erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,39 @@ def test_landed_cost_voucher_stock_impact(self):
178178
self.assertEqual(last_sle.qty_after_transaction, last_sle_after_landed_cost.qty_after_transaction)
179179
self.assertEqual(last_sle_after_landed_cost.stock_value - last_sle.stock_value, 50.0)
180180

181+
def test_lcv_validates_company(self):
182+
from erpnext.stock.doctype.landed_cost_voucher.landed_cost_voucher import (
183+
IncorrectCompanyValidationError,
184+
)
185+
186+
company_a = "_Test Company"
187+
company_b = "_Test Company with perpetual inventory"
188+
189+
pr = make_purchase_receipt(
190+
company=company_a,
191+
warehouse="Stores - _TC",
192+
qty=1,
193+
rate=100,
194+
)
195+
196+
lcv = make_landed_cost_voucher(
197+
company=company_b,
198+
receipt_document_type="Purchase Receipt",
199+
receipt_document=pr.name,
200+
charges=50,
201+
do_not_save=True,
202+
)
203+
204+
self.assertRaises(IncorrectCompanyValidationError, lcv.validate_receipt_documents)
205+
lcv.company = company_a
206+
207+
self.assertRaises(IncorrectCompanyValidationError, lcv.validate_expense_accounts)
208+
lcv.taxes[0].expense_account = get_expense_account(company_a)
209+
210+
lcv.save()
211+
distribute_landed_cost_on_items(lcv)
212+
lcv.submit()
213+
181214
def test_landed_cost_voucher_for_zero_purchase_rate(self):
182215
"Test impact of LCV on future stock balances."
183216
from erpnext.stock.doctype.item.test_item import make_item
@@ -1260,6 +1293,7 @@ def make_landed_cost_voucher(**args):
12601293
lcv = frappe.new_doc("Landed Cost Voucher")
12611294
lcv.company = args.company or "_Test Company"
12621295
lcv.distribute_charges_based_on = args.distribute_charges_based_on or "Amount"
1296+
expense_account = get_expense_account(args.company or "_Test Company")
12631297

12641298
lcv.set(
12651299
"purchase_receipts",
@@ -1280,7 +1314,7 @@ def make_landed_cost_voucher(**args):
12801314
[
12811315
{
12821316
"description": "Shipping Charges",
1283-
"expense_account": args.expense_account or "Expenses Included In Valuation - TCP1",
1317+
"expense_account": args.expense_account or expense_account,
12841318
"amount": args.charges,
12851319
}
12861320
],
@@ -1300,6 +1334,7 @@ def create_landed_cost_voucher(receipt_document_type, receipt_document, company,
13001334
lcv = frappe.new_doc("Landed Cost Voucher")
13011335
lcv.company = company
13021336
lcv.distribute_charges_based_on = "Amount"
1337+
expense_account = get_expense_account(company)
13031338

13041339
lcv.set(
13051340
"purchase_receipts",
@@ -1319,7 +1354,7 @@ def create_landed_cost_voucher(receipt_document_type, receipt_document, company,
13191354
[
13201355
{
13211356
"description": "Insurance Charges",
1322-
"expense_account": "Expenses Included In Valuation - TCP1",
1357+
"expense_account": expense_account,
13231358
"amount": charges,
13241359
}
13251360
],
@@ -1334,6 +1369,11 @@ def create_landed_cost_voucher(receipt_document_type, receipt_document, company,
13341369
return lcv
13351370

13361371

1372+
def get_expense_account(company):
1373+
company_abbr = frappe.get_cached_value("Company", company, "abbr")
1374+
return f"Expenses Included In Valuation - {company_abbr}"
1375+
1376+
13371377
def distribute_landed_cost_on_items(lcv):
13381378
based_on = lcv.distribute_charges_based_on.lower()
13391379
total = sum(flt(d.get(based_on)) for d in lcv.get("items"))

0 commit comments

Comments
 (0)