From bf61014fe58a52d462f09fc3f4f69d7344cfedf4 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 19 Jun 2025 13:01:51 +0530 Subject: [PATCH] test: purchase invoice provisional accounting entry (backport #48112) (#48134) test: purchase invoice provisional accounting entry (#48112) * test: fixed purchase invoice provisional accounting entry * test: added tests for multi currency (cherry picked from commit 80f992c87f5d9dd9fbff3e680beb2b776da85670) Co-authored-by: Diptanil Saha --- .../purchase_invoice/purchase_invoice.py | 8 +- .../purchase_invoice/test_purchase_invoice.py | 129 ++++++++++++++---- 2 files changed, 110 insertions(+), 27 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 805e76ad64c..fdfb50a6f42 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -1226,7 +1226,7 @@ class PurchaseInvoice(BuyingController): pr_items = frappe.get_all( "Purchase Receipt Item", filters={"parent": ("in", linked_purchase_receipts)}, - fields=["name", "provisional_expense_account", "qty", "base_rate"], + fields=["name", "provisional_expense_account", "qty", "base_rate", "rate"], ) default_provisional_account = self.get_company_default("default_provisional_account") provisional_accounts = set( @@ -1254,6 +1254,7 @@ class PurchaseInvoice(BuyingController): "provisional_account": item.provisional_expense_account or default_provisional_account, "qty": item.qty, "base_rate": item.base_rate, + "rate": item.rate, "has_provisional_entry": item.name in rows_with_provisional_entries, } @@ -1270,7 +1271,10 @@ class PurchaseInvoice(BuyingController): self.posting_date, pr_item.get("provisional_account"), reverse=1, - item_amount=(min(item.qty, pr_item.get("qty")) * pr_item.get("base_rate")), + item_amount=( + (min(item.qty, pr_item.get("qty")) * pr_item.get("rate")) + * purchase_receipt_doc.get("conversion_rate") + ), ) def update_gross_purchase_amount_for_linked_assets(self, item): diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 99eb1de2cf8..f0446b35e5d 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -1663,7 +1663,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): pi = create_purchase_invoice_from_receipt(pr.name) pi.set_posting_time = 1 - pi.posting_date = add_days(pr.posting_date, -1) + pi.posting_date = add_days(pr.posting_date, 1) pi.items[0].expense_account = "Cost of Goods Sold - _TC" pi.save() pi.submit() @@ -1672,30 +1672,38 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): # Check GLE for Purchase Invoice expected_gle = [ - ["Cost of Goods Sold - _TC", 250, 0, add_days(pr.posting_date, -1)], - ["Creditors - _TC", 0, 250, add_days(pr.posting_date, -1)], + ["Cost of Goods Sold - _TC", 250, 0, add_days(pr.posting_date, 1)], + ["Creditors - _TC", 0, 250, add_days(pr.posting_date, 1)], ] check_gl_entries(self, pi.name, expected_gle, pi.posting_date) expected_gle_for_purchase_receipt = [ - ["Provision Account - _TC", 250, 0, pr.posting_date], - ["_Test Account Cost for Goods Sold - _TC", 0, 250, pr.posting_date], - ["Provision Account - _TC", 0, 250, pi.posting_date], - ["_Test Account Cost for Goods Sold - _TC", 250, 0, pi.posting_date], + ["_Test Account Cost for Goods Sold - _TC", 250, 0, pr.posting_date], + ["Provision Account - _TC", 0, 250, pr.posting_date], + ["_Test Account Cost for Goods Sold - _TC", 0, 250, pi.posting_date], + ["Provision Account - _TC", 250, 0, pi.posting_date], ] - check_gl_entries(self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date) + check_gl_entries( + self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date, voucher_type="Purchase Receipt" + ) # Cancel purchase invoice to check reverse provisional entry cancellation pi.cancel() expected_gle_for_purchase_receipt_post_pi_cancel = [ - ["Provision Account - _TC", 0, 250, pi.posting_date], ["_Test Account Cost for Goods Sold - _TC", 250, 0, pi.posting_date], + ["Provision Account - _TC", 0, 250, pi.posting_date], ] - check_gl_entries(self, pr.name, expected_gle_for_purchase_receipt_post_pi_cancel, pr.posting_date) + check_gl_entries( + self, + pr.name, + expected_gle_for_purchase_receipt_post_pi_cancel, + pi.posting_date, + voucher_type="Purchase Receipt", + ) toggle_provisional_accounting_setting() @@ -1716,7 +1724,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): # Overbill PR: rate = 2000, qty = 10 pi = create_purchase_invoice_from_receipt(pr.name) pi.set_posting_time = 1 - pi.posting_date = add_days(pr.posting_date, -1) + pi.posting_date = add_days(pr.posting_date, 1) pi.items[0].qty = 10 pi.items[0].rate = 2000 pi.items[0].expense_account = "Cost of Goods Sold - _TC" @@ -1724,30 +1732,38 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): pi.submit() expected_gle = [ - ["Cost of Goods Sold - _TC", 20000, 0, add_days(pr.posting_date, -1)], - ["Creditors - _TC", 0, 20000, add_days(pr.posting_date, -1)], + ["Cost of Goods Sold - _TC", 20000, 0, add_days(pr.posting_date, 1)], + ["Creditors - _TC", 0, 20000, add_days(pr.posting_date, 1)], ] check_gl_entries(self, pi.name, expected_gle, pi.posting_date) expected_gle_for_purchase_receipt = [ - ["Provision Account - _TC", 5000, 0, pr.posting_date], - ["_Test Account Cost for Goods Sold - _TC", 0, 5000, pr.posting_date], - ["Provision Account - _TC", 0, 5000, pi.posting_date], - ["_Test Account Cost for Goods Sold - _TC", 5000, 0, pi.posting_date], + ["_Test Account Cost for Goods Sold - _TC", 5000, 0, pr.posting_date], + ["Provision Account - _TC", 0, 5000, pr.posting_date], + ["_Test Account Cost for Goods Sold - _TC", 0, 5000, pi.posting_date], + ["Provision Account - _TC", 5000, 0, pi.posting_date], ] - check_gl_entries(self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date) + check_gl_entries( + self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date, voucher_type="Purchase Receipt" + ) # Cancel purchase invoice to check reverse provisional entry cancellation pi.cancel() expected_gle_for_purchase_receipt_post_pi_cancel = [ - ["Provision Account - _TC", 0, 5000, pi.posting_date], ["_Test Account Cost for Goods Sold - _TC", 5000, 0, pi.posting_date], + ["Provision Account - _TC", 0, 5000, pi.posting_date], ] - check_gl_entries(self, pr.name, expected_gle_for_purchase_receipt_post_pi_cancel, pr.posting_date) + check_gl_entries( + self, + pr.name, + expected_gle_for_purchase_receipt_post_pi_cancel, + pi.posting_date, + voucher_type="Purchase Receipt", + ) toggle_provisional_accounting_setting() @@ -1780,13 +1796,76 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): check_gl_entries(self, pi.name, expected_gle, pi.posting_date) expected_gle_for_purchase_receipt = [ - ["Provision Account - _TC", 5000, 0, pr.posting_date], - ["_Test Account Cost for Goods Sold - _TC", 0, 5000, pr.posting_date], - ["Provision Account - _TC", 0, 1000, pi.posting_date], - ["_Test Account Cost for Goods Sold - _TC", 1000, 0, pi.posting_date], + ["_Test Account Cost for Goods Sold - _TC", 5000, 0, pr.posting_date], + ["Provision Account - _TC", 0, 5000, pr.posting_date], + ["_Test Account Cost for Goods Sold - _TC", 0, 1000, pi.posting_date], + ["Provision Account - _TC", 1000, 0, pi.posting_date], ] - check_gl_entries(self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date) + check_gl_entries( + self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date, voucher_type="Purchase Receipt" + ) + + toggle_provisional_accounting_setting() + + def test_provisional_accounting_entry_multi_currency(self): + setup_provisional_accounting() + + pr = make_purchase_receipt( + item_code="_Test Non Stock Item", + posting_date=add_days(nowdate(), -2), + qty=1000, + rate=111.11, + currency="USD", + do_not_save=1, + supplier="_Test Supplier USD", + ) + pr.conversion_rate = 0.014783000 + pr.save() + pr.submit() + + pi = create_purchase_invoice_from_receipt(pr.name) + pi.set_posting_time = 1 + pi.posting_date = add_days(pr.posting_date, 1) + pi.items[0].expense_account = "Cost of Goods Sold - _TC" + pi.save() + pi.submit() + + self.assertEqual(pr.items[0].provisional_expense_account, "Provision Account - _TC") + + # Check GLE for Purchase Invoice + expected_gle = [ + ["_Test Payable USD - _TC", 0, 1642.54, add_days(pr.posting_date, 1)], + ["Cost of Goods Sold - _TC", 1642.54, 0, add_days(pr.posting_date, 1)], + ] + + check_gl_entries(self, pi.name, expected_gle, pi.posting_date) + + expected_gle_for_purchase_receipt = [ + ["_Test Account Cost for Goods Sold - _TC", 1642.54, 0, pr.posting_date], + ["Provision Account - _TC", 0, 1642.54, pr.posting_date], + ["_Test Account Cost for Goods Sold - _TC", 0, 1642.54, pi.posting_date], + ["Provision Account - _TC", 1642.54, 0, pi.posting_date], + ] + check_gl_entries( + self, pr.name, expected_gle_for_purchase_receipt, pr.posting_date, voucher_type="Purchase Receipt" + ) + + # Cancel purchase invoice to check reverse provisional entry cancellation + pi.cancel() + + expected_gle_for_purchase_receipt_post_pi_cancel = [ + ["_Test Account Cost for Goods Sold - _TC", 1642.54, 0, pi.posting_date], + ["Provision Account - _TC", 0, 1642.54, pi.posting_date], + ] + + check_gl_entries( + self, + pr.name, + expected_gle_for_purchase_receipt_post_pi_cancel, + pi.posting_date, + voucher_type="Purchase Receipt", + ) toggle_provisional_accounting_setting()