diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index bccd29c822a..9002f3cbd66 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -2935,6 +2935,86 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): pi.save() self.assertEqual(pi.discount_amount, discount_amount) +<<<<<<< HEAD +======= + def test_returned_item_purchase_receipt(self): + from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import ( + make_purchase_receipt as make_purchase_receipt_from_pi, + ) + + item = create_item("_Test Returned Item Purchase Receipt", is_stock_item=1) + + pi = make_purchase_invoice(item_code=item.name, qty=5, rate=100) + + return_pi = make_purchase_invoice( + item_code=item.name, + is_return=1, + return_against=pi.name, + qty=-5, + do_not_submit=True, + ) + + return_pi.items[0].purchase_invoice_item = pi.items[0].name + return_pi.submit() + + pr = make_purchase_receipt_from_pi(pi.name) + self.assertFalse(pr.items) + + @ERPNextTestSuite.change_settings("Accounts Settings", {"enable_common_party_accounting": True}) + def test_purchase_invoice_return_common_party_je_has_no_negative_amounts(self): + from erpnext.accounts.doctype.opening_invoice_creation_tool.test_opening_invoice_creation_tool import ( + make_customer, + ) + from erpnext.accounts.doctype.party_link.party_link import create_party_link + from erpnext.controllers.sales_and_purchase_return import make_return_doc + + customer = make_customer(customer="_Test Common Party Return PI") + supplier = create_supplier(supplier_name="_Test Common Party Return PI").name + # Supplier must be secondary so get_common_party_link finds it via the PI's party_type + party_link = create_party_link("Customer", customer, supplier) + + pi = make_purchase_invoice(supplier=supplier, parent_cost_center="_Test Cost Center - _TC") + + return_pi = make_return_doc(pi.doctype, pi.name) + return_pi.submit() + + # JE for the return should credit the supplier (secondary/reconciliation) account + # and debit the customer (primary) account — all positive amounts + jv_accounts = frappe.get_all( + "Journal Entry Account", + filters={"reference_type": return_pi.doctype, "reference_name": return_pi.name, "docstatus": 1}, + fields=["debit_in_account_currency", "credit_in_account_currency", "account"], + ) + + self.assertTrue(jv_accounts, "Expected a Journal Entry for the return invoice") + for row in jv_accounts: + self.assertGreaterEqual( + row.debit_in_account_currency, + 0, + f"Negative debit on account {row.account}", + ) + self.assertGreaterEqual( + row.credit_in_account_currency, + 0, + f"Negative credit on account {row.account}", + ) + + # Supplier (secondary) account must be credited, not debited + supplier_row = next(r for r in jv_accounts if r.account == pi.credit_to) + self.assertGreater(supplier_row.credit_in_account_currency, 0) + self.assertEqual(supplier_row.debit_in_account_currency, 0) + + party_link.delete() + + def test_purchase_invoice_cancellation_post_account_freezing_date(self): + pi = make_purchase_invoice() + frappe.db.set_value("Company", "_Test Company", "accounts_frozen_till_date", add_days(getdate(), 1)) + try: + self.assertRaises(frappe.ValidationError, pi.cancel) + finally: + frappe.db.set_value("Company", "_Test Company", "accounts_frozen_till_date", None) + +>>>>>>> f4b827cb3d (fix: honor account freezing date when cancelling vouchers) def set_advance_flag(company, flag, default_account): frappe.db.set_value( diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py index 599173c99f5..fff2becf2bb 100644 --- a/erpnext/accounts/general_ledger.py +++ b/erpnext/accounts/general_ledger.py @@ -697,7 +697,7 @@ def make_reverse_gl_entries( partial_cancel=partial_cancel, ) validate_accounting_period(gl_entries) - check_freezing_date(gl_entries[0]["posting_date"], adv_adj) + check_freezing_date(gl_entries[0]["posting_date"], gl_entries[0]["company"], adv_adj) is_opening = any(d.get("is_opening") == "Yes" for d in gl_entries)