From 706a6c1ad7c7850974d7dc7b6a0ff162ef4c1a28 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 28 Jun 2024 20:28:01 +0530 Subject: [PATCH 1/4] fix: always post to tax account heads if LCV is booked (cherry picked from commit 0fcd5d51309ed3fd2dfcc16d44d31489990848d1) --- .../stock/doctype/purchase_receipt/purchase_receipt.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 3136cdffeffc..a8cb7fd83b42 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -776,6 +776,13 @@ def add_provisional_gl_entry( posting_date=posting_date, ) + def is_landed_cost_booked_for_any_item(self) -> bool: + for x in self.items: + if x.landed_cost_voucher_amount != 0: + return True + + return False + def make_tax_gl_entries(self, gl_entries, via_landed_cost_voucher=False): negative_expense_to_be_booked = sum([flt(d.item_tax_amount) for d in self.get("items")]) is_asset_pr = any(d.is_fixed_asset for d in self.get("items")) @@ -811,7 +818,7 @@ def make_tax_gl_entries(self, gl_entries, via_landed_cost_voucher=False): i = 1 for tax in self.get("taxes"): if valuation_tax.get(tax.name): - if via_landed_cost_voucher: + if via_landed_cost_voucher or self.is_landed_cost_booked_for_any_item(): account = tax.account_head else: negative_expense_booked_in_pi = frappe.db.sql( From b7cbafae140918087ca43ac9d9427669fb52a849 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 1 Jul 2024 17:50:36 +0530 Subject: [PATCH 2/4] test: Repost should not merge expense accounts from LCV (cherry picked from commit fa56555150a36d2880f0d409c4924ca7bbab121d) --- .../purchase_receipt/test_purchase_receipt.py | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 16553749d0a0..6ddf756a7a23 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -3020,6 +3020,142 @@ def test_purchase_return_from_rejected_warehouse(self): self.assertEqual(pr_return.items[0].rejected_qty, 0.0) self.assertEqual(pr_return.items[0].rejected_warehouse, "") + def test_tax_account_heads_on_lcv_and_item_repost(self): + """ + PO -> PR -> PI + PR -> LCV + Backdated `Repost Item valuation` should not merge tax account heads into stock_rbnb + """ + from erpnext.accounts.doctype.account.test_account import create_account + from erpnext.buying.doctype.purchase_order.test_purchase_order import ( + create_purchase_order, + make_pr_against_po, + ) + from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice + + stock_rbnb = "Stock Received But Not Billed - _TC" + stock_in_hand = "Stock In Hand - _TC" + test_cc = "_Test Cost Center - _TC" + test_company = "_Test Company" + creditors = "Creditors - _TC" + lcv_expense_account = "Expenses Included In Valuation - _TC" + + company_doc = frappe.get_doc("Company", test_company) + company_doc.enable_perpetual_inventory = True + company_doc.stock_received_but_not_billed = stock_rbnb + company_doc.save() + + packaging_charges_account = create_account( + account_name="Packaging Charges", + parent_account="Indirect Expenses - _TC", + company=test_company, + account_type="Tax", + ) + + po = create_purchase_order(qty=10, rate=100, do_not_save=1) + po.taxes = [] + po.append( + "taxes", + { + "category": "Valuation and Total", + "account_head": packaging_charges_account, + "cost_center": test_cc, + "description": "Test", + "add_deduct_tax": "Add", + "charge_type": "Actual", + "tax_amount": 250, + }, + ) + po.save().submit() + + pr = make_pr_against_po(po.name, received_qty=10) + pr_gl_entries = get_gl_entries(pr.doctype, pr.name, skip_cancelled=True) + expected_pr_gles = [ + {"account": stock_rbnb, "debit": 0.0, "credit": 1000.0, "cost_center": test_cc}, + {"account": stock_in_hand, "debit": 1250.0, "credit": 0.0, "cost_center": test_cc}, + {"account": packaging_charges_account, "debit": 0.0, "credit": 250.0, "cost_center": test_cc}, + ] + self.assertEqual(expected_pr_gles, pr_gl_entries) + + # Make PI against Purchase Receipt + pi = make_purchase_invoice(pr.name).save().submit() + pi_gl_entries = get_gl_entries(pi.doctype, pi.name, skip_cancelled=True) + expected_pi_gles = [ + {"account": stock_rbnb, "debit": 1000.0, "credit": 0.0, "cost_center": test_cc}, + {"account": packaging_charges_account, "debit": 250.0, "credit": 0.0, "cost_center": test_cc}, + {"account": creditors, "debit": 0.0, "credit": 1250.0, "cost_center": None}, + ] + self.assertEqual(expected_pi_gles, pi_gl_entries) + + self.create_lcv(pr.doctype, pr.name, test_company, lcv_expense_account) + pr_gles_after_lcv = get_gl_entries(pr.doctype, pr.name, skip_cancelled=True) + expected_pr_gles_after_lcv = [ + {"account": stock_rbnb, "debit": 0.0, "credit": 1000.0, "cost_center": test_cc}, + {"account": stock_in_hand, "debit": 1300.0, "credit": 0.0, "cost_center": test_cc}, + {"account": packaging_charges_account, "debit": 0.0, "credit": 250.0, "cost_center": test_cc}, + {"account": lcv_expense_account, "debit": 0.0, "credit": 50.0, "cost_center": test_cc}, + ] + self.assertEqual(expected_pr_gles_after_lcv, pr_gles_after_lcv) + + # Trigger Repost Item Valudation on a older date + repost_doc = frappe.get_doc( + { + "doctype": "Repost Item Valuation", + "based_on": "Item and Warehouse", + "item_code": pr.items[0].item_code, + "warehouse": pr.items[0].warehouse, + "posting_date": add_days(pr.posting_date, -1), + "posting_time": "00:00:00", + "company": pr.company, + "allow_negative_stock": 1, + "via_landed_cost_voucher": 0, + "allow_zero_rate": 0, + } + ) + repost_doc.save().submit() + + pr_gles_after_repost = get_gl_entries(pr.doctype, pr.name, skip_cancelled=True) + expected_pr_gles_after_repost = [ + {"account": stock_rbnb, "debit": 0.0, "credit": 1000.0, "cost_center": test_cc}, + {"account": stock_in_hand, "debit": 1300.0, "credit": 0.0, "cost_center": test_cc}, + {"account": packaging_charges_account, "debit": 0.0, "credit": 250.0, "cost_center": test_cc}, + {"account": lcv_expense_account, "debit": 0.0, "credit": 50.0, "cost_center": test_cc}, + ] + self.assertEqual(len(pr_gles_after_repost), len(expected_pr_gles_after_repost)) + self.assertEqual(expected_pr_gles_after_repost, pr_gles_after_repost) + + def create_lcv(self, receipt_document_type, receipt_document, company, expense_account, charges=50): + ref_doc = frappe.get_doc(receipt_document_type, receipt_document) + + lcv = frappe.new_doc("Landed Cost Voucher") + lcv.company = company + lcv.distribute_charges_based_on = "Qty" + lcv.set( + "purchase_receipts", + [ + { + "receipt_document_type": receipt_document_type, + "receipt_document": receipt_document, + "supplier": ref_doc.supplier, + "posting_date": ref_doc.posting_date, + "grand_total": ref_doc.base_grand_total, + } + ], + ) + + lcv.set( + "taxes", + [ + { + "description": "Testing", + "expense_account": expense_account, + "amount": charges, + } + ], + ) + lcv.save().submit() + return lcv + def prepare_data_for_internal_transfer(): from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier From e55fd7204a3ead3793c18099f9ad8c33fc632cf4 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 2 Jul 2024 12:45:04 +0530 Subject: [PATCH 3/4] refactor(test): cleanup test data (cherry picked from commit 6ba6b5aa33a6a5d9f3ad042dd9cf2c423960dd55) --- .../purchase_receipt/test_purchase_receipt.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 6ddf756a7a23..d92de03b3411 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -3087,7 +3087,7 @@ def test_tax_account_heads_on_lcv_and_item_repost(self): ] self.assertEqual(expected_pi_gles, pi_gl_entries) - self.create_lcv(pr.doctype, pr.name, test_company, lcv_expense_account) + lcv = self.create_lcv(pr.doctype, pr.name, test_company, lcv_expense_account) pr_gles_after_lcv = get_gl_entries(pr.doctype, pr.name, skip_cancelled=True) expected_pr_gles_after_lcv = [ {"account": stock_rbnb, "debit": 0.0, "credit": 1000.0, "cost_center": test_cc}, @@ -3124,6 +3124,18 @@ def test_tax_account_heads_on_lcv_and_item_repost(self): self.assertEqual(len(pr_gles_after_repost), len(expected_pr_gles_after_repost)) self.assertEqual(expected_pr_gles_after_repost, pr_gles_after_repost) + # teardown + lcv.reload() + lcv.cancel() + pi.reload() + pi.cancel() + pr.reload() + pr.cancel() + + company_doc.enable_perpetual_inventory = False + company_doc.stock_received_but_not_billed = None + company_doc.save() + def create_lcv(self, receipt_document_type, receipt_document, company, expense_account, charges=50): ref_doc = frappe.get_doc(receipt_document_type, receipt_document) From c3cc36364896bcc759a05ad535017bad76d987bf Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 2 Jul 2024 17:00:16 +0530 Subject: [PATCH 4/4] refactor(test): fix flaky test (cherry picked from commit 0e256b8b29d2779bf84c3adb311cc3b122dd4b42) --- erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index d92de03b3411..968cb68dac06 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -3043,6 +3043,7 @@ def test_tax_account_heads_on_lcv_and_item_repost(self): company_doc = frappe.get_doc("Company", test_company) company_doc.enable_perpetual_inventory = True company_doc.stock_received_but_not_billed = stock_rbnb + company_doc.default_inventory_account = stock_in_hand company_doc.save() packaging_charges_account = create_account( @@ -3134,6 +3135,7 @@ def test_tax_account_heads_on_lcv_and_item_repost(self): company_doc.enable_perpetual_inventory = False company_doc.stock_received_but_not_billed = None + company_doc.default_inventory_account = None company_doc.save() def create_lcv(self, receipt_document_type, receipt_document, company, expense_account, charges=50):