From 7726271e2ac6776b29f795e6e54dd76aa6d581b8 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 1 Jun 2022 14:17:06 +0530 Subject: [PATCH] fix: purchase invoice return GLe voucher_wise_stock_value contains tuples and the condition was looking for string, so it's never triggered. Caused by https://github.com/frappe/erpnext/pull/24200 --- .../purchase_invoice/purchase_invoice.py | 2 +- .../purchase_invoice/test_purchase_invoice.py | 77 ++++++++++++++++++- .../controllers/sales_and_purchase_return.py | 2 +- erpnext/stock/tests/test_utils.py | 17 ++++ 4 files changed, 95 insertions(+), 3 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index e6da6669ac22..5d11dffdef8d 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -1127,7 +1127,7 @@ def make_stock_adjustment_entry( # Stock ledger value is not matching with the warehouse amount if ( self.update_stock - and voucher_wise_stock_value.get(item.name) + and voucher_wise_stock_value.get((item.name, item.warehouse)) and warehouse_debit_amount != flt(voucher_wise_stock_value.get((item.name, item.warehouse)), net_amt_precision) ): diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 30d26acf3a2d..9c8a6dd6b26f 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -27,12 +27,13 @@ make_purchase_receipt, ) from erpnext.stock.doctype.stock_entry.test_stock_entry import get_qty_after_transaction +from erpnext.stock.tests.test_utils import StockTestMixin test_dependencies = ["Item", "Cost Center", "Payment Term", "Payment Terms Template"] test_ignore = ["Serial No"] -class TestPurchaseInvoice(unittest.TestCase): +class TestPurchaseInvoice(unittest.TestCase, StockTestMixin): @classmethod def setUpClass(self): unlink_payment_on_cancel_of_invoice() @@ -693,6 +694,80 @@ def test_return_purchase_invoice_with_perpetual_inventory(self): self.assertEqual(expected_values[gle.account][0], gle.debit) self.assertEqual(expected_values[gle.account][1], gle.credit) + def test_standalone_return_using_pi(self): + from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry + + item = self.make_item().name + company = "_Test Company with perpetual inventory" + warehouse = "Stores - TCP1" + + make_stock_entry(item_code=item, target=warehouse, qty=50, rate=120) + + return_pi = make_purchase_invoice( + is_return=1, + item=item, + qty=-10, + update_stock=1, + rate=100, + company=company, + warehouse=warehouse, + cost_center="Main - TCP1", + ) + + # assert that stock consumption is with actual rate + self.assertGLEs( + return_pi, + [{"credit": 1200, "debit": 0}], + gle_filters={"account": "Stock In Hand - TCP1"}, + ) + + # assert loss booked in COGS + self.assertGLEs( + return_pi, + [{"credit": 0, "debit": 200}], + gle_filters={"account": "Cost of Goods Sold - TCP1"}, + ) + + def test_return_with_lcv(self): + from erpnext.controllers.sales_and_purchase_return import make_return_doc + from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import ( + create_landed_cost_voucher, + ) + + item = self.make_item().name + company = "_Test Company with perpetual inventory" + warehouse = "Stores - TCP1" + cost_center = "Main - TCP1" + + pi = make_purchase_invoice( + item=item, + company=company, + warehouse=warehouse, + cost_center=cost_center, + update_stock=1, + qty=10, + rate=100, + ) + + # Create landed cost voucher - will increase valuation of received item by 10 + create_landed_cost_voucher("Purchase Invoice", pi.name, pi.company, charges=100) + return_pi = make_return_doc(pi.doctype, pi.name) + return_pi.save().submit() + + # assert that stock consumption is with actual in rate + self.assertGLEs( + return_pi, + [{"credit": 1100, "debit": 0}], + gle_filters={"account": "Stock In Hand - TCP1"}, + ) + + # assert loss booked in COGS + self.assertGLEs( + return_pi, + [{"credit": 0, "debit": 100}], + gle_filters={"account": "Cost of Goods Sold - TCP1"}, + ) + def test_multi_currency_gle(self): pi = make_purchase_invoice( supplier="_Test Supplier USD", diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index bd4b59b38559..d24ac3f2cf34 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -316,7 +316,7 @@ def get_returned_qty_map_for_row(return_against, party, row_name, doctype): return data[0] -def make_return_doc(doctype, source_name, target_doc=None): +def make_return_doc(doctype: str, source_name: str, target_doc=None): from frappe.model.mapper import get_mapped_doc from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos diff --git a/erpnext/stock/tests/test_utils.py b/erpnext/stock/tests/test_utils.py index e07e08c79e5a..b046dbda24f7 100644 --- a/erpnext/stock/tests/test_utils.py +++ b/erpnext/stock/tests/test_utils.py @@ -38,6 +38,23 @@ def assertSLEs(self, doc, expected_sles, sle_filters=None): self.assertEqual(v, act_value, msg=f"{k} doesn't match \n{exp_sle}\n{act_sle}") + def assertGLEs(self, doc, expected_gles, gle_filters=None, order_by=None): + filters = {"voucher_no": doc.name, "voucher_type": doc.doctype, "is_cancelled": 0} + + if gle_filters: + filters.update(gle_filters) + actual_gles = frappe.get_all( + "GL Entry", + fields=["*"], + filters=filters, + order_by=order_by or "posting_date, creation", + ) + + for exp_gle, act_gle in zip(expected_gles, actual_gles): + for k, exp_value in exp_gle.items(): + act_value = act_gle[k] + self.assertEqual(exp_value, act_value, msg=f"{k} doesn't match \n{exp_gle}\n{act_gle}") + class TestStockUtilities(FrappeTestCase, StockTestMixin): def test_barcode_scanning(self):