mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-26 10:08:30 +00:00
Merge pull request #54476 from ljain112/fix-tds-threshhold
fix: ensure tax withholding entries respect date range of category
This commit is contained in:
@@ -5,8 +5,7 @@ import datetime
|
||||
from unittest.mock import patch
|
||||
|
||||
import frappe
|
||||
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||
from frappe.utils import add_days, add_months, today
|
||||
from frappe.utils import add_days, add_months, getdate, today
|
||||
|
||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
@@ -1922,7 +1921,6 @@ class TestTaxWithholdingCategory(ERPNextTestSuite):
|
||||
|
||||
def set_previous_fy_and_tax_category(self):
|
||||
test_company = "_Test Company"
|
||||
category = "Cumulative Threshold TDS"
|
||||
|
||||
def add_company_to_fy(fy, company):
|
||||
if not [x.company for x in fy.companies if x.company == company]:
|
||||
@@ -1948,20 +1946,6 @@ class TestTaxWithholdingCategory(ERPNextTestSuite):
|
||||
)
|
||||
self.prev_fy.save()
|
||||
|
||||
# setup tax withholding category for previous fiscal year
|
||||
cat = frappe.get_doc("Tax Withholding Category", category)
|
||||
cat.append(
|
||||
"rates",
|
||||
{
|
||||
"from_date": self.prev_fy.year_start_date,
|
||||
"to_date": self.prev_fy.year_end_date,
|
||||
"tax_withholding_rate": 10,
|
||||
"single_threshold": 0,
|
||||
"cumulative_threshold": 30000,
|
||||
},
|
||||
)
|
||||
cat.save()
|
||||
|
||||
def test_tds_across_fiscal_year(self):
|
||||
"""
|
||||
Advance TDS on previous fiscal year should be properly allocated on Invoices in upcoming fiscal year
|
||||
@@ -1972,6 +1956,14 @@ class TestTaxWithholdingCategory(ERPNextTestSuite):
|
||||
supplier = "Test TDS Supplier"
|
||||
# Cumulative threshold 30000 and tax rate 10%
|
||||
category = "Cumulative Threshold TDS"
|
||||
create_tax_withholding_category(
|
||||
category_name=category,
|
||||
rate=10,
|
||||
from_date=self.prev_fy.year_start_date,
|
||||
to_date=self.prev_fy.year_end_date,
|
||||
account="TDS - _TC",
|
||||
cumulative_threshold=30000,
|
||||
)
|
||||
frappe.db.set_value(
|
||||
"Supplier",
|
||||
supplier,
|
||||
@@ -2043,6 +2035,158 @@ class TestTaxWithholdingCategory(ERPNextTestSuite):
|
||||
self.assertEqual(pi2.taxes, [])
|
||||
self.assertEqual(payment.taxes[0].tax_amount, 6000)
|
||||
|
||||
def test_threshold_resets_in_new_fiscal_year(self):
|
||||
"""
|
||||
Threshold entries from a previous FY must not carry over into the new FY.
|
||||
"""
|
||||
self.set_previous_fy_and_tax_category()
|
||||
invoices = []
|
||||
supplier = "Test TDS Supplier"
|
||||
category = "Cumulative Threshold TDS"
|
||||
create_tax_withholding_category(
|
||||
category_name=category,
|
||||
rate=10,
|
||||
from_date=self.prev_fy.year_start_date,
|
||||
to_date=self.prev_fy.year_end_date,
|
||||
account="TDS - _TC",
|
||||
cumulative_threshold=30000,
|
||||
)
|
||||
self.setup_party_with_category("Supplier", supplier, category)
|
||||
prev_fy_date = add_days(self.prev_fy.year_end_date, -10)
|
||||
|
||||
# Previous FY: 3 invoices to cross the 30000 cumulative threshold
|
||||
for _ in range(3):
|
||||
pi = create_purchase_invoice(supplier=supplier, posting_date=prev_fy_date, set_posting_time=True)
|
||||
pi.submit()
|
||||
invoices.append(pi)
|
||||
|
||||
# Third invoice crosses the threshold - 3000 TDS deducted across all three
|
||||
self.validate_tax_deduction(invoices[-1], 3000)
|
||||
|
||||
# Current FY: 10000 invoice - must be Under Withheld, threshold resets
|
||||
pi_curr = create_purchase_invoice(supplier=supplier)
|
||||
pi_curr.submit()
|
||||
invoices.append(pi_curr)
|
||||
self.validate_tax_deduction(pi_curr, 0)
|
||||
|
||||
self.validate_tax_withholding_entries(
|
||||
"Purchase Invoice",
|
||||
pi_curr.name,
|
||||
[
|
||||
self.get_tax_withholding_entry(
|
||||
tax_withholding_category=category,
|
||||
party_type="Supplier",
|
||||
party=supplier,
|
||||
taxable_doctype="Purchase Invoice",
|
||||
taxable_name=pi_curr.name,
|
||||
tax_rate=10.0,
|
||||
taxable_amount=10000.0,
|
||||
withholding_amount=0.0,
|
||||
status="Under Withheld",
|
||||
withholding_doctype=None,
|
||||
withholding_name=None,
|
||||
under_withheld_reason=None,
|
||||
)
|
||||
],
|
||||
)
|
||||
self.cleanup_invoices(invoices)
|
||||
|
||||
def test_tax_on_excess_threshold_resets_in_new_fiscal_year(self):
|
||||
"""
|
||||
For tax-on-excess categories, unused threshold must reset each FY.
|
||||
"""
|
||||
self.set_previous_fy_and_tax_category()
|
||||
invoices = []
|
||||
supplier = "Test TDS Supplier3"
|
||||
category = "New TDS Category"
|
||||
create_tax_withholding_category(
|
||||
category_name=category,
|
||||
rate=10,
|
||||
from_date=self.prev_fy.year_start_date,
|
||||
to_date=self.prev_fy.year_end_date,
|
||||
account="TDS - _TC",
|
||||
cumulative_threshold=30000,
|
||||
tax_on_excess_amount=1,
|
||||
round_off_tax_amount=1,
|
||||
)
|
||||
self.setup_party_with_category("Supplier", supplier, category)
|
||||
prev_fy_date = add_days(self.prev_fy.year_end_date, -10)
|
||||
|
||||
for _ in range(2):
|
||||
pi = create_purchase_invoice(supplier=supplier, posting_date=prev_fy_date, set_posting_time=True)
|
||||
pi.submit()
|
||||
invoices.append(pi)
|
||||
|
||||
pi3 = create_purchase_invoice(
|
||||
supplier=supplier, rate=20000, posting_date=prev_fy_date, set_posting_time=True
|
||||
)
|
||||
pi3.submit()
|
||||
invoices.append(pi3)
|
||||
|
||||
self.validate_tax_deduction(pi3, 1000)
|
||||
self.validate_tax_withholding_entries(
|
||||
"Purchase Invoice",
|
||||
pi3.name,
|
||||
[
|
||||
self.get_tax_withholding_entry(
|
||||
tax_withholding_category=category,
|
||||
party_type="Supplier",
|
||||
party=supplier,
|
||||
taxable_doctype="Purchase Invoice",
|
||||
taxable_name=pi3.name,
|
||||
tax_rate=10.0,
|
||||
taxable_amount=10000.0,
|
||||
withholding_amount=0.0,
|
||||
status="Settled",
|
||||
withholding_doctype="Purchase Invoice",
|
||||
withholding_name=pi3.name,
|
||||
under_withheld_reason="Threshold Exemption",
|
||||
),
|
||||
self.get_tax_withholding_entry(
|
||||
tax_withholding_category=category,
|
||||
party_type="Supplier",
|
||||
party=supplier,
|
||||
taxable_doctype="Purchase Invoice",
|
||||
taxable_name=pi3.name,
|
||||
tax_rate=10.0,
|
||||
taxable_amount=10000.0,
|
||||
withholding_amount=1000.0,
|
||||
status="Settled",
|
||||
withholding_doctype="Purchase Invoice",
|
||||
withholding_name=pi3.name,
|
||||
under_withheld_reason=None,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
# no excess, so no TDS
|
||||
pi_curr = create_purchase_invoice(supplier=supplier, rate=30000)
|
||||
pi_curr.submit()
|
||||
invoices.append(pi_curr)
|
||||
self.validate_tax_deduction(pi_curr, 0)
|
||||
|
||||
self.validate_tax_withholding_entries(
|
||||
"Purchase Invoice",
|
||||
pi_curr.name,
|
||||
[
|
||||
self.get_tax_withholding_entry(
|
||||
tax_withholding_category=category,
|
||||
party_type="Supplier",
|
||||
party=supplier,
|
||||
taxable_doctype="Purchase Invoice",
|
||||
taxable_name=pi_curr.name,
|
||||
tax_rate=10.0,
|
||||
taxable_amount=30000.0,
|
||||
withholding_amount=0.0,
|
||||
status="Settled",
|
||||
withholding_doctype="Purchase Invoice",
|
||||
withholding_name=pi_curr.name,
|
||||
under_withheld_reason="Threshold Exemption",
|
||||
),
|
||||
],
|
||||
)
|
||||
self.cleanup_invoices(invoices)
|
||||
|
||||
@ERPNextTestSuite.change_settings("Accounts Settings", {"delete_linked_ledger_entries": 1})
|
||||
def test_tds_payment_entry_cancellation(self):
|
||||
"""
|
||||
@@ -3997,7 +4141,7 @@ def create_tax_withholding_category(
|
||||
tax_deduction_basis="Net Total",
|
||||
):
|
||||
if not frappe.db.exists("Tax Withholding Category", category_name):
|
||||
frappe.get_doc(
|
||||
doc = frappe.get_doc(
|
||||
{
|
||||
"doctype": "Tax Withholding Category",
|
||||
"name": category_name,
|
||||
@@ -4018,6 +4162,22 @@ def create_tax_withholding_category(
|
||||
"accounts": [{"company": "_Test Company", "account": account}],
|
||||
}
|
||||
).insert()
|
||||
else:
|
||||
doc = frappe.get_doc("Tax Withholding Category", category_name)
|
||||
if not any(getdate(r.from_date) == getdate(from_date) for r in doc.rates):
|
||||
doc.append(
|
||||
"rates",
|
||||
{
|
||||
"from_date": from_date,
|
||||
"to_date": to_date,
|
||||
"tax_withholding_rate": rate,
|
||||
"single_threshold": single_threshold,
|
||||
"cumulative_threshold": cumulative_threshold,
|
||||
},
|
||||
)
|
||||
doc.save()
|
||||
|
||||
return doc
|
||||
|
||||
|
||||
def create_lower_deduction_certificate(
|
||||
|
||||
@@ -642,6 +642,7 @@ class TaxWithholdingController:
|
||||
.where(entry.tax_withholding_category == category.name)
|
||||
.where(entry.company == self.doc.company)
|
||||
.where(entry.docstatus == 1)
|
||||
.where(entry.taxable_date.between(category.from_date, category.to_date))
|
||||
.groupby(entry.status)
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user