From 216a46bd6615aab47a30ff79ddf78503080121c1 Mon Sep 17 00:00:00 2001 From: marination Date: Mon, 27 Mar 2023 16:11:00 +0530 Subject: [PATCH] feat: Make Tax loss booking optional - Checkbox in Accounts Settings - Apply checkbox in PE deductions setting logic - Adjust tests --- .../accounts_settings/accounts_settings.json | 10 +++++- .../doctype/payment_entry/payment_entry.py | 17 +++++++--- .../payment_entry/test_payment_entry.py | 34 ++++++++++++++----- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index 3f985b640bf1..c0eed18ad1be 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -31,6 +31,7 @@ "determine_address_tax_category_from", "column_break_19", "add_taxes_from_item_tax_template", + "book_tax_discount_loss", "print_settings", "show_inclusive_tax_in_print", "column_break_12", @@ -360,6 +361,13 @@ "fieldname": "show_balance_in_coa", "fieldtype": "Check", "label": "Show Balances in Chart Of Accounts" + }, + { + "default": "0", + "description": "Split Early Payment Discount Loss into Income and Tax Loss", + "fieldname": "book_tax_discount_loss", + "fieldtype": "Check", + "label": "Book Tax Loss on Early Payment Discount" } ], "icon": "icon-cog", @@ -367,7 +375,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-01-02 12:07:42.434214", + "modified": "2023-03-28 09:50:20.375233", "modified_by": "Administrator", "module": "Accounts", "name": "Accounts Settings", diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 15fd0c61eb42..c34bddd77ebd 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -1824,7 +1824,10 @@ def get_payment_entry( pe.set_amounts() if discount_amount: - base_total_discount_loss = set_early_payment_discount_loss(pe, doc, valid_discounts) + base_total_discount_loss = 0 + if frappe.db.get_single_value("Accounts Settings", "book_tax_discount_loss"): + base_total_discount_loss = split_early_payment_discount_loss(pe, doc, valid_discounts) + set_pending_discount_loss( pe, doc, discount_amount, base_total_discount_loss, party_account_currency ) @@ -1991,19 +1994,25 @@ def set_pending_discount_loss( # Avoid considering miniscule losses discount_amount = flt(discount_amount - base_total_discount_loss, doc.precision("grand_total")) - # If pending base discount amount (mostly rounding loss), set it in deductions + # Set base discount amount (discount loss/pending rounding loss) in deductions if discount_amount > 0.0: positive_negative = -1 if pe.payment_type == "Pay" else 1 + + # If tax loss booking is enabled, pending loss will be rounding loss. + # Otherwise it will be the total discount loss. + book_tax_loss = frappe.db.get_single_value("Accounts Settings", "book_tax_discount_loss") + account_type = "round_off_account" if book_tax_loss else "default_discount_account" + pe.set_gain_or_loss( account_details={ - "account": frappe.get_cached_value("Company", pe.company, "round_off_account"), + "account": frappe.get_cached_value("Company", pe.company, account_type), "cost_center": pe.cost_center or frappe.get_cached_value("Company", pe.company, "cost_center"), "amount": discount_amount * positive_negative, } ) -def set_early_payment_discount_loss(pe, doc, valid_discounts) -> float: +def split_early_payment_discount_loss(pe, doc, valid_discounts) -> float: """Split early payment discount into Income Loss & Tax Loss.""" total_discount_percent = get_total_discount_percent(doc, valid_discounts) diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index ef57c99bdaa1..67049c47ad05 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -256,17 +256,24 @@ def test_payment_entry_against_payment_terms_with_discount(self): }, ) si.save() - si.submit() + frappe.db.set_single_value("Accounts Settings", "book_tax_discount_loss", 1) + pe_with_tax_loss = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Cash - _TC") + + self.assertEqual(pe_with_tax_loss.references[0].payment_term, "30 Credit Days with 10% Discount") + self.assertEqual(pe_with_tax_loss.references[0].allocated_amount, 236.0) + self.assertEqual(pe_with_tax_loss.paid_amount, 212.4) + self.assertEqual(pe_with_tax_loss.deductions[0].amount, 20.0) # Loss on Income + self.assertEqual(pe_with_tax_loss.deductions[1].amount, 3.6) # Loss on Tax + self.assertEqual(pe_with_tax_loss.deductions[1].account, "_Test Account Service Tax - _TC") + + frappe.db.set_single_value("Accounts Settings", "book_tax_discount_loss", 0) pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Cash - _TC") - self.assertEqual(pe.references[0].payment_term, "30 Credit Days with 10% Discount") self.assertEqual(pe.references[0].allocated_amount, 236.0) self.assertEqual(pe.paid_amount, 212.4) - self.assertEqual(pe.deductions[0].amount, 20.0) # Loss on Income - self.assertEqual(pe.deductions[1].amount, 3.6) # Loss on Tax - self.assertEqual(pe.deductions[1].account, "_Test Account Service Tax - _TC") + self.assertEqual(pe.deductions[0].amount, 23.6) pe.submit() si.load_from_db() @@ -311,12 +318,18 @@ def test_payment_entry_against_payment_terms_with_discount_amount(self): ) self.assertEqual(pe_1.paid_amount, 236.0) # discount not applied + # Test if tax loss is booked on enabling configuration + frappe.db.set_single_value("Accounts Settings", "book_tax_discount_loss", 1) + pe_with_tax_loss = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Cash - _TC") + self.assertEqual(pe_with_tax_loss.deductions[0].amount, 42.37) # Loss on Income + self.assertEqual(pe_with_tax_loss.deductions[1].amount, 7.63) # Loss on Tax + self.assertEqual(pe_with_tax_loss.deductions[1].account, "_Test Account Service Tax - _TC") + + frappe.db.set_single_value("Accounts Settings", "book_tax_discount_loss", 0) pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Cash - _TC") self.assertEqual(pe.references[0].allocated_amount, 236.0) self.assertEqual(pe.paid_amount, 186) - self.assertEqual(pe.deductions[0].amount, 42.37) # Loss on Income - self.assertEqual(pe.deductions[1].amount, 7.63) # Loss on Tax - self.assertEqual(pe.deductions[1].account, "_Test Account Service Tax - _TC") + self.assertEqual(pe.deductions[0].amount, 50.0) pe.submit() si.load_from_db() @@ -328,7 +341,10 @@ def test_payment_entry_against_payment_terms_with_discount_amount(self): @change_settings( "Accounts Settings", - {"allow_multi_currency_invoices_against_single_party_account": 1}, + { + "allow_multi_currency_invoices_against_single_party_account": 1, + "book_tax_discount_loss": 1, + }, ) def test_payment_entry_multicurrency_si_with_base_currency_accounting_early_payment_discount( self,