From c5ce4db315f955f7c0c95c51667f98c27139463f Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 25 Jan 2024 14:05:42 +0530 Subject: [PATCH 1/4] refactor: prevent '{debit/credit}_to' account mismatch (cherry picked from commit 6f2fae1b6133286ab882e421e69f6a87ecb97d4a) # Conflicts: # erpnext/controllers/accounts_controller.py --- erpnext/controllers/accounts_controller.py | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index ac197259679..f1385c721d8 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -187,6 +187,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 := [ @@ -320,6 +321,32 @@ class AccountsController(TransactionBase): (self.doctype, self.name), ) +<<<<<<< HEAD +======= + def remove_serial_and_batch_bundle(self): + bundles = frappe.get_all( + "Serial and Batch Bundle", + filters={"voucher_type": self.doctype, "voucher_no": self.name, "docstatus": ("!=", 1)}, + ) + + 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) + ) + ) + +>>>>>>> 6f2fae1b61 (refactor: prevent '{debit/credit}_to' account mismatch) def validate_deferred_income_expense_account(self): field_map = { "Sales Invoice": "deferred_revenue_account", From faeca79c689987a0a666d5f2bf5e56a2a6a5661a Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 25 Jan 2024 14:21:18 +0530 Subject: [PATCH 2/4] test: account mismatch validation (cherry picked from commit 8bdc76073367d4a912524f16bf098d94340f50c5) --- .../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 45a01ab04aa..abf0fc5c0f3 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1531,6 +1531,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 9212a74913d653c857f6d9b692fe83ea96a148ce Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 25 Jan 2024 14:29:07 +0530 Subject: [PATCH 3/4] test: debit note account mismatch (cherry picked from commit bdca718103a98eba64e69715eaf628dfd9377d5e) # Conflicts: # erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py --- .../purchase_invoice/test_purchase_invoice.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index dc2b37291e8..f17c60bcd09 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -1893,6 +1893,55 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): self.assertEqual(pi.items[0].cost_center, "_Test Cost Center Buying - _TC") +<<<<<<< HEAD +======= + 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 = "" + pi.save() + + self.assertFalse(pi.items[0].item_code) + pi.submit() + + return_pi = make_purchase_invoice( + item_name="_Test Item", + is_return=1, + return_against=pi.name, + qty=-10, + do_not_save=True, + ) + return_pi.items[0].item_code = "" + return_pi.save() + return_pi.submit() + self.assertEqual(return_pi.docstatus, 1) + + +def set_advance_flag(company, flag, default_account): + frappe.db.set_value( + "Company", + company, + { + "book_advance_payments_in_separate_party_account": flag, + "default_advance_paid_account": default_account, + }, + ) + +>>>>>>> bdca718103 (test: debit note account mismatch) def check_gl_entries( doc, From 0884c5ed83048a71db3947fd5d3df119b7a7d408 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 30 Jan 2024 11:03:25 +0530 Subject: [PATCH 4/4] chore: resolve conflicts --- .../purchase_invoice/test_purchase_invoice.py | 34 ------------------- erpnext/controllers/accounts_controller.py | 12 ------- 2 files changed, 46 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index f17c60bcd09..6942e28726f 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -1893,8 +1893,6 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): self.assertEqual(pi.items[0].cost_center, "_Test Cost Center Buying - _TC") -<<<<<<< HEAD -======= def test_debit_note_with_account_mismatch(self): new_creditors = create_account( parent_account="Accounts Payable - _TC", @@ -1910,38 +1908,6 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): 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 = "" - pi.save() - - self.assertFalse(pi.items[0].item_code) - pi.submit() - - return_pi = make_purchase_invoice( - item_name="_Test Item", - is_return=1, - return_against=pi.name, - qty=-10, - do_not_save=True, - ) - return_pi.items[0].item_code = "" - return_pi.save() - return_pi.submit() - self.assertEqual(return_pi.docstatus, 1) - - -def set_advance_flag(company, flag, default_account): - frappe.db.set_value( - "Company", - company, - { - "book_advance_payments_in_separate_party_account": flag, - "default_advance_paid_account": default_account, - }, - ) - ->>>>>>> bdca718103 (test: debit note account mismatch) def check_gl_entries( doc, diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index f1385c721d8..a4597da8e27 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -321,17 +321,6 @@ class AccountsController(TransactionBase): (self.doctype, self.name), ) -<<<<<<< HEAD -======= - def remove_serial_and_batch_bundle(self): - bundles = frappe.get_all( - "Serial and Batch Bundle", - filters={"voucher_type": self.doctype, "voucher_no": self.name, "docstatus": ("!=", 1)}, - ) - - 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 @@ -346,7 +335,6 @@ class AccountsController(TransactionBase): ) ) ->>>>>>> 6f2fae1b61 (refactor: prevent '{debit/credit}_to' account mismatch) def validate_deferred_income_expense_account(self): field_map = { "Sales Invoice": "deferred_revenue_account",