From 6f2fae1b6133286ab882e421e69f6a87ecb97d4a Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 25 Jan 2024 14:05:42 +0530 Subject: [PATCH 1/3] refactor: prevent '{debit/credit}_to' account mismatch --- erpnext/controllers/accounts_controller.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 1ed719d2e6..a0569ec63e 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -202,6 +202,7 @@ class AccountsController(TransactionBase): self.validate_party() self.validate_currency() self.validate_party_account_currency() + self.validate_return_against_account() if self.doctype in ["Purchase Invoice", "Sales Invoice"]: if invalid_advances := [ @@ -350,6 +351,20 @@ class AccountsController(TransactionBase): for bundle in bundles: frappe.delete_doc("Serial and Batch Bundle", bundle.name) + def validate_return_against_account(self): + if ( + self.doctype in ["Sales Invoice", "Purchase Invoice"] and self.is_return and self.return_against + ): + cr_dr_account_field = "debit_to" if self.doctype == "Sales Invoice" else "credit_to" + cr_dr_account_label = "Debit To" if self.doctype == "Sales Invoice" else "Credit To" + cr_dr_account = self.get(cr_dr_account_field) + if frappe.get_value(self.doctype, self.return_against, cr_dr_account_field) != cr_dr_account: + frappe.throw( + _("'{0}' account: '{1}' should match the Return Against Invoice").format( + frappe.bold(cr_dr_account_label), frappe.bold(cr_dr_account) + ) + ) + def validate_deferred_income_expense_account(self): field_map = { "Sales Invoice": "deferred_revenue_account", From 8bdc76073367d4a912524f16bf098d94340f50c5 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 25 Jan 2024 14:21:18 +0530 Subject: [PATCH 2/3] test: account mismatch validation --- .../doctype/sales_invoice/test_sales_invoice.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 672fec2fee..8c3aedebcd 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1550,6 +1550,19 @@ class TestSalesInvoice(FrappeTestCase): self.assertEqual(frappe.db.get_value("Sales Invoice", si1.name, "outstanding_amount"), -1000) self.assertEqual(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"), 2500) + def test_return_invoice_with_account_mismatch(self): + debtors2 = create_account( + parent_account="Accounts Receivable - _TC", + account_name="Debtors 2", + company="_Test Company", + account_type="Receivable", + ) + si = create_sales_invoice(qty=1, rate=1000) + cr_note = create_sales_invoice( + qty=-1, rate=1000, is_return=1, return_against=si.name, debit_to=debtors2, do_not_save=True + ) + self.assertRaises(frappe.ValidationError, cr_note.save) + def test_gle_made_when_asset_is_returned(self): create_asset_data() asset = create_asset(item_code="Macbook Pro") From bdca718103a98eba64e69715eaf628dfd9377d5e Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 25 Jan 2024 14:29:07 +0530 Subject: [PATCH 3/3] test: debit note account mismatch --- .../purchase_invoice/test_purchase_invoice.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 992fbe6e02..5da6f8bdcc 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -1995,6 +1995,21 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): self.assertEqual(pi.items[0].cost_center, "_Test Cost Center Buying - _TC") + def test_debit_note_with_account_mismatch(self): + new_creditors = create_account( + parent_account="Accounts Payable - _TC", + account_name="Creditors 2", + company="_Test Company", + account_type="Payable", + ) + pi = make_purchase_invoice(qty=1, rate=1000) + dr_note = make_purchase_invoice( + qty=-1, rate=1000, is_return=1, return_against=pi.name, do_not_save=True + ) + dr_note.credit_to = new_creditors + + self.assertRaises(frappe.ValidationError, dr_note.save) + def test_debit_note_without_item(self): pi = make_purchase_invoice(item_name="_Test Item", qty=10, do_not_submit=True) pi.items[0].item_code = ""