From 83ccb32be68c55b050e6b1993da2d9a8af5d7c67 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 29 Feb 2024 09:04:24 +0530 Subject: [PATCH 1/6] fix: add LCV flag to determine negative expenses (cherry picked from commit baa3fee1bf9ce814a889ecf264fb6bac4ebaf93c) # Conflicts: # erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py --- erpnext/controllers/stock_controller.py | 4 +-- .../landed_cost_voucher.py | 5 ++++ .../purchase_receipt/purchase_receipt.py | 27 +++++++++---------- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index 4f579fd500e..bc8778b4505 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -97,7 +97,7 @@ class StockController(AccountsController): ) ) - def make_gl_entries(self, gl_entries=None, from_repost=False): + def make_gl_entries(self, gl_entries=None, from_repost=False, via_landed_cost_voucher=False): if self.docstatus == 2: make_reverse_gl_entries(voucher_type=self.doctype, voucher_no=self.name) @@ -118,7 +118,7 @@ class StockController(AccountsController): if self.docstatus == 1: if not gl_entries: - gl_entries = self.get_gl_entries(warehouse_account) + gl_entries = self.get_gl_entries(warehouse_account, via_landed_cost_voucher) make_gl_entries(gl_entries, from_repost=from_repost) def validate_serialized_batch(self): 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 683e946298a..da974c73999 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -252,8 +252,13 @@ class LandedCostVoucher(Document): doc.docstatus = 1 doc.make_bundle_using_old_serial_batch_fields(via_landed_cost_voucher=True) doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True) +<<<<<<< HEAD doc.make_gl_entries() doc.repost_future_sle_and_gle(via_landed_cost_voucher=True) +======= + doc.make_gl_entries(via_landed_cost_voucher=True) + doc.repost_future_sle_and_gle() +>>>>>>> baa3fee1bf (fix: add LCV flag to determine negative expenses) def validate_asset_qty_and_status(self, receipt_document_type, receipt_document): for item in self.get("items"): diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 0742ba3b590..6a00fed5588 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -422,13 +422,13 @@ class PurchaseReceipt(BuyingController): self.delete_auto_created_batches() self.set_consumed_qty_in_subcontract_order() - def get_gl_entries(self, warehouse_account=None): + def get_gl_entries(self, warehouse_account=None, via_landed_cost_voucher=False): from erpnext.accounts.general_ledger import process_gl_map gl_entries = [] self.make_item_gl_entries(gl_entries, warehouse_account=warehouse_account) - self.make_tax_gl_entries(gl_entries) + self.make_tax_gl_entries(gl_entries, via_landed_cost_voucher) update_regional_gl_entries(gl_entries, self) return process_gl_map(gl_entries) @@ -776,7 +776,7 @@ class PurchaseReceipt(BuyingController): posting_date=posting_date, ) - def make_tax_gl_entries(self, gl_entries): + 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")) # Cost center-wise amount breakup for other charges included for valuation @@ -811,18 +811,17 @@ class PurchaseReceipt(BuyingController): i = 1 for tax in self.get("taxes"): if valuation_tax.get(tax.name): - negative_expense_booked_in_pi = frappe.db.sql( - """select name from `tabPurchase Invoice Item` pi - where docstatus = 1 and purchase_receipt=%s - and exists(select name from `tabGL Entry` where voucher_type='Purchase Invoice' - and voucher_no=pi.parent and account=%s)""", - (self.name, tax.account_head), - ) - - if negative_expense_booked_in_pi: - account = stock_rbnb - else: + if via_landed_cost_voucher: account = tax.account_head + else: + negative_expense_booked_in_pi = frappe.db.sql( + """select name from `tabPurchase Invoice Item` pi + where docstatus = 1 and purchase_receipt=%s + and exists(select name from `tabGL Entry` where voucher_type='Purchase Invoice' + and voucher_no=pi.parent and account=%s)""", + (self.name, tax.account_head), + ) + account = stock_rbnb if negative_expense_booked_in_pi else tax.account_head if i == len(valuation_tax): applicable_amount = amount_including_divisional_loss From c7c9d33954b78a8b0f3926cf3daa99bc382cd215 Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 29 Feb 2024 11:26:31 +0530 Subject: [PATCH 2/6] test: LCV entries after billing (cherry picked from commit 53642e7417c54197ba526625902d2671a7a564c2) # Conflicts: # erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py --- erpnext/controllers/stock_controller.py | 6 +- .../purchase_receipt/test_purchase_receipt.py | 69 +++++++++++++++++-- 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py index bc8778b4505..212c9adf4af 100644 --- a/erpnext/controllers/stock_controller.py +++ b/erpnext/controllers/stock_controller.py @@ -118,7 +118,11 @@ class StockController(AccountsController): if self.docstatus == 1: if not gl_entries: - gl_entries = self.get_gl_entries(warehouse_account, via_landed_cost_voucher) + gl_entries = ( + self.get_gl_entries(warehouse_account, via_landed_cost_voucher) + if self.doctype == "Purchase Receipt" + else self.get_gl_entries(warehouse_account) + ) make_gl_entries(gl_entries, from_repost=from_repost) def validate_serialized_batch(self): diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 88e9c94c2b1..497dd331f7a 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -2426,6 +2426,7 @@ class TestPurchaseReceipt(FrappeTestCase): pr.reload() self.assertEqual(pr.per_billed, 100) +<<<<<<< HEAD def test_purchase_receipt_with_use_serial_batch_field_for_rejected_qty(self): batch_item = make_item( "_Test Purchase Receipt Batch Item For Rejected Qty", @@ -2912,6 +2913,50 @@ class TestPurchaseReceipt(FrappeTestCase): "Serial and Batch Bundle", return_pr.items[0].rejected_serial_and_batch_bundle, "total_qty" ), ) +======= + def test_valuation_taxes_lcv_repost_after_billing(self): + from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import ( + make_landed_cost_voucher, + ) + + company = frappe.get_doc("Company", "_Test Company") + company.enable_perpetual_inventory = 1 + company.default_inventory_account = "Stock In Hand - _TC" + company.stock_received_but_not_billed = "Stock Received But Not Billed - _TC" + company.save() + + pr = make_purchase_receipt(qty=10, rate=1000, do_not_submit=1) + pr.append( + "taxes", + { + "category": "Valuation and Total", + "charge_type": "Actual", + "account_head": "Freight and Forwarding Charges - _TC", + "tax_amount": 2000, + "description": "Test", + }, + ) + pr.submit() + pi = make_purchase_invoice(pr.name) + pi.submit() + lcv = make_landed_cost_voucher( + company=pr.company, + receipt_document_type="Purchase Receipt", + receipt_document=pr.name, + charges=2000, + distribute_charges_based_on="Qty", + expense_account="Expenses Included In Valuation - _TC", + ) + + gl_entries = get_gl_entries("Purchase Receipt", pr.name, skip_cancelled=True, as_dict=False) + expected_gle = ( + ("Stock Received But Not Billed - _TC", 0, 10000, "Main - _TC"), + ("Stock In Hand - _TC", 14000, 0, "Main - _TC"), + ("Freight and Forwarding Charges - _TC", 0, 2000, "Main - _TC"), + ("Expenses Included In Valuation - _TC", 0, 2000, "Main - _TC"), + ) + self.assertSequenceEqual(expected_gle, gl_entries) +>>>>>>> 53642e7417 (test: LCV entries after billing) def prepare_data_for_internal_transfer(): @@ -2959,14 +3004,24 @@ def get_sl_entries(voucher_type, voucher_no): ) -def get_gl_entries(voucher_type, voucher_no): - return frappe.db.sql( - """select account, debit, credit, cost_center, is_cancelled - from `tabGL Entry` where voucher_type=%s and voucher_no=%s - order by account desc""", - (voucher_type, voucher_no), - as_dict=1, +def get_gl_entries(voucher_type, voucher_no, skip_cancelled=False, as_dict=True): + gl = frappe.qb.DocType("GL Entry") + gl_query = ( + frappe.qb.from_(gl) + .select( + gl.account, + gl.debit, + gl.credit, + gl.cost_center, + ) + .where((gl.voucher_type == voucher_type) & (gl.voucher_no == voucher_no)) + .orderby(gl.account, order=frappe.qb.desc) ) + if skip_cancelled: + gl_query = gl_query.where(gl.is_cancelled == 0) + else: + gl_query = gl_query.select(gl.is_cancelled) + return gl_query.run(as_dict=as_dict) def get_taxes(**args): From 8618402829d9553ddc0c7d7ac41d86147ab2a84d Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 29 Feb 2024 11:58:14 +0530 Subject: [PATCH 3/6] fix: parameters for PI references (cherry picked from commit 8b3d46610eacd27edbceaefff6452efb68a83365) # Conflicts: # erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py # erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py --- .../doctype/landed_cost_voucher/landed_cost_voucher.py | 7 +++++++ .../doctype/purchase_receipt/test_purchase_receipt.py | 4 ++++ 2 files changed, 11 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 da974c73999..70874af677b 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -252,11 +252,18 @@ class LandedCostVoucher(Document): doc.docstatus = 1 doc.make_bundle_using_old_serial_batch_fields(via_landed_cost_voucher=True) doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True) +<<<<<<< HEAD <<<<<<< HEAD doc.make_gl_entries() doc.repost_future_sle_and_gle(via_landed_cost_voucher=True) ======= doc.make_gl_entries(via_landed_cost_voucher=True) +======= + if d.receipt_document_type == "Purchase Receipt": + doc.make_gl_entries(via_landed_cost_voucher=True) + else: + doc.make_gl_entries() +>>>>>>> 8b3d46610e (fix: parameters for PI references) doc.repost_future_sle_and_gle() >>>>>>> baa3fee1bf (fix: add LCV flag to determine negative expenses) diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 497dd331f7a..30b72a96c7d 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -2956,7 +2956,11 @@ class TestPurchaseReceipt(FrappeTestCase): ("Expenses Included In Valuation - _TC", 0, 2000, "Main - _TC"), ) self.assertSequenceEqual(expected_gle, gl_entries) +<<<<<<< HEAD >>>>>>> 53642e7417 (test: LCV entries after billing) +======= + frappe.db.rollback() +>>>>>>> 8b3d46610e (fix: parameters for PI references) def prepare_data_for_internal_transfer(): From 4c11f2bff23102eff34146baa15521218e31b77a Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Thu, 29 Feb 2024 13:04:01 +0530 Subject: [PATCH 4/6] fix: reset perpetual inventory flag after test (cherry picked from commit 0b36cbe307fec68f72ddfdfdeee401134887a884) # Conflicts: # erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py --- .../purchase_receipt/test_purchase_receipt.py | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index 30b72a96c7d..a7a54f4f5c2 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -9,6 +9,7 @@ from pypika import functions as fn import erpnext from erpnext.accounts.doctype.account.test_account import get_inventory_account from erpnext.controllers.buying_controller import QtyMismatchError +from erpnext.stock import get_warehouse_account_map from erpnext.stock.doctype.item.test_item import create_item, make_item from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice from erpnext.stock.doctype.serial_and_batch_bundle.serial_and_batch_bundle import ( @@ -1681,7 +1682,6 @@ class TestPurchaseReceipt(FrappeTestCase): frappe.db.set_single_value("Stock Settings", "over_delivery_receipt_allowance", 0) def test_internal_pr_gl_entries(self): - from erpnext.stock import get_warehouse_account_map from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry @@ -2919,11 +2919,14 @@ class TestPurchaseReceipt(FrappeTestCase): make_landed_cost_voucher, ) - company = frappe.get_doc("Company", "_Test Company") - company.enable_perpetual_inventory = 1 - company.default_inventory_account = "Stock In Hand - _TC" - company.stock_received_but_not_billed = "Stock Received But Not Billed - _TC" - company.save() + old_perpetual_inventory = erpnext.is_perpetual_inventory_enabled("_Test Company") + frappe.local.enable_perpetual_inventory["_Test Company"] = 1 + frappe.db.set_value( + "Company", + "_Test Company", + "stock_received_but_not_billed", + "Stock Received But Not Billed - _TC", + ) pr = make_purchase_receipt(qty=10, rate=1000, do_not_submit=1) pr.append( @@ -2939,7 +2942,7 @@ class TestPurchaseReceipt(FrappeTestCase): pr.submit() pi = make_purchase_invoice(pr.name) pi.submit() - lcv = make_landed_cost_voucher( + make_landed_cost_voucher( company=pr.company, receipt_document_type="Purchase Receipt", receipt_document=pr.name, @@ -2949,18 +2952,23 @@ class TestPurchaseReceipt(FrappeTestCase): ) gl_entries = get_gl_entries("Purchase Receipt", pr.name, skip_cancelled=True, as_dict=False) + warehouse_account = get_warehouse_account_map("_Test Company") expected_gle = ( ("Stock Received But Not Billed - _TC", 0, 10000, "Main - _TC"), - ("Stock In Hand - _TC", 14000, 0, "Main - _TC"), ("Freight and Forwarding Charges - _TC", 0, 2000, "Main - _TC"), ("Expenses Included In Valuation - _TC", 0, 2000, "Main - _TC"), + (warehouse_account[pr.items[0].warehouse]["account"], 14000, 0, "Main - _TC"), ) self.assertSequenceEqual(expected_gle, gl_entries) <<<<<<< HEAD +<<<<<<< HEAD >>>>>>> 53642e7417 (test: LCV entries after billing) ======= frappe.db.rollback() >>>>>>> 8b3d46610e (fix: parameters for PI references) +======= + frappe.local.enable_perpetual_inventory["_Test Company"] = old_perpetual_inventory +>>>>>>> 0b36cbe307 (fix: reset perpetual inventory flag after test) def prepare_data_for_internal_transfer(): From 248e9cac712afbaf92302f11f8baa9ec420fbf3a Mon Sep 17 00:00:00 2001 From: Gursheen Anand Date: Sun, 21 Apr 2024 19:07:08 +0530 Subject: [PATCH 5/6] chore: resolve conflicts (cherry picked from commit 54a58e9205af43f4aabe1668e8d8cf925a226536) # Conflicts: # erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py --- .../stock/doctype/landed_cost_voucher/landed_cost_voucher.py | 4 ++++ 1 file changed, 4 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 70874af677b..0d15338c37c 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -263,9 +263,13 @@ class LandedCostVoucher(Document): doc.make_gl_entries(via_landed_cost_voucher=True) else: doc.make_gl_entries() +<<<<<<< HEAD >>>>>>> 8b3d46610e (fix: parameters for PI references) doc.repost_future_sle_and_gle() >>>>>>> baa3fee1bf (fix: add LCV flag to determine negative expenses) +======= + doc.repost_future_sle_and_gle(via_landed_cost_voucher=True) +>>>>>>> 54a58e9205 (chore: resolve conflicts) def validate_asset_qty_and_status(self, receipt_document_type, receipt_document): for item in self.get("items"): From b577d95ecd9893313258b69ed67297e32aea7c40 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Sun, 16 Jun 2024 20:47:55 +0530 Subject: [PATCH 6/6] chore: resolve conflicts --- .../landed_cost_voucher/landed_cost_voucher.py | 13 ------------- .../purchase_receipt/test_purchase_receipt.py | 11 +---------- 2 files changed, 1 insertion(+), 23 deletions(-) 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 0d15338c37c..eb84fdbc7c0 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py @@ -252,24 +252,11 @@ class LandedCostVoucher(Document): doc.docstatus = 1 doc.make_bundle_using_old_serial_batch_fields(via_landed_cost_voucher=True) doc.update_stock_ledger(allow_negative_stock=True, via_landed_cost_voucher=True) -<<<<<<< HEAD -<<<<<<< HEAD - doc.make_gl_entries() - doc.repost_future_sle_and_gle(via_landed_cost_voucher=True) -======= - doc.make_gl_entries(via_landed_cost_voucher=True) -======= if d.receipt_document_type == "Purchase Receipt": doc.make_gl_entries(via_landed_cost_voucher=True) else: doc.make_gl_entries() -<<<<<<< HEAD ->>>>>>> 8b3d46610e (fix: parameters for PI references) - doc.repost_future_sle_and_gle() ->>>>>>> baa3fee1bf (fix: add LCV flag to determine negative expenses) -======= doc.repost_future_sle_and_gle(via_landed_cost_voucher=True) ->>>>>>> 54a58e9205 (chore: resolve conflicts) def validate_asset_qty_and_status(self, receipt_document_type, receipt_document): for item in self.get("items"): diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index a7a54f4f5c2..42747818d2b 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -2426,7 +2426,6 @@ class TestPurchaseReceipt(FrappeTestCase): pr.reload() self.assertEqual(pr.per_billed, 100) -<<<<<<< HEAD def test_purchase_receipt_with_use_serial_batch_field_for_rejected_qty(self): batch_item = make_item( "_Test Purchase Receipt Batch Item For Rejected Qty", @@ -2913,7 +2912,7 @@ class TestPurchaseReceipt(FrappeTestCase): "Serial and Batch Bundle", return_pr.items[0].rejected_serial_and_batch_bundle, "total_qty" ), ) -======= + def test_valuation_taxes_lcv_repost_after_billing(self): from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import ( make_landed_cost_voucher, @@ -2960,15 +2959,7 @@ class TestPurchaseReceipt(FrappeTestCase): (warehouse_account[pr.items[0].warehouse]["account"], 14000, 0, "Main - _TC"), ) self.assertSequenceEqual(expected_gle, gl_entries) -<<<<<<< HEAD -<<<<<<< HEAD ->>>>>>> 53642e7417 (test: LCV entries after billing) -======= - frappe.db.rollback() ->>>>>>> 8b3d46610e (fix: parameters for PI references) -======= frappe.local.enable_perpetual_inventory["_Test Company"] = old_perpetual_inventory ->>>>>>> 0b36cbe307 (fix: reset perpetual inventory flag after test) def prepare_data_for_internal_transfer():