Skip to content

Commit 9ead8d4

Browse files
committed
fix: ensure tax withholding entries respect date range of category
1 parent 3faeb16 commit 9ead8d4

2 files changed

Lines changed: 179 additions & 18 deletions

File tree

erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py

Lines changed: 178 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
from unittest.mock import patch
66

77
import frappe
8-
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
9-
from frappe.utils import add_days, add_months, today
8+
from frappe.utils import add_days, add_months, getdate, today
109

1110
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
1211
from erpnext.accounts.utils import get_fiscal_year
@@ -1922,7 +1921,6 @@ def test_payment_entry_with_ldc_and_partial_invoice_adjustment(self):
19221921

19231922
def set_previous_fy_and_tax_category(self):
19241923
test_company = "_Test Company"
1925-
category = "Cumulative Threshold TDS"
19261924

19271925
def add_company_to_fy(fy, company):
19281926
if not [x.company for x in fy.companies if x.company == company]:
@@ -1948,20 +1946,6 @@ def add_company_to_fy(fy, company):
19481946
)
19491947
self.prev_fy.save()
19501948

1951-
# setup tax withholding category for previous fiscal year
1952-
cat = frappe.get_doc("Tax Withholding Category", category)
1953-
cat.append(
1954-
"rates",
1955-
{
1956-
"from_date": self.prev_fy.year_start_date,
1957-
"to_date": self.prev_fy.year_end_date,
1958-
"tax_withholding_rate": 10,
1959-
"single_threshold": 0,
1960-
"cumulative_threshold": 30000,
1961-
},
1962-
)
1963-
cat.save()
1964-
19651949
def test_tds_across_fiscal_year(self):
19661950
"""
19671951
Advance TDS on previous fiscal year should be properly allocated on Invoices in upcoming fiscal year
@@ -1972,6 +1956,14 @@ def test_tds_across_fiscal_year(self):
19721956
supplier = "Test TDS Supplier"
19731957
# Cumulative threshold 30000 and tax rate 10%
19741958
category = "Cumulative Threshold TDS"
1959+
create_tax_withholding_category(
1960+
category_name=category,
1961+
rate=10,
1962+
from_date=self.prev_fy.year_start_date,
1963+
to_date=self.prev_fy.year_end_date,
1964+
account="TDS - _TC",
1965+
cumulative_threshold=30000,
1966+
)
19751967
frappe.db.set_value(
19761968
"Supplier",
19771969
supplier,
@@ -2043,6 +2035,158 @@ def test_tds_across_fiscal_year(self):
20432035
self.assertEqual(pi2.taxes, [])
20442036
self.assertEqual(payment.taxes[0].tax_amount, 6000)
20452037

2038+
def test_threshold_resets_in_new_fiscal_year(self):
2039+
"""
2040+
Threshold entries from a previous FY must not carry over into the new FY.
2041+
"""
2042+
self.set_previous_fy_and_tax_category()
2043+
invoices = []
2044+
supplier = "Test TDS Supplier"
2045+
category = "Cumulative Threshold TDS"
2046+
create_tax_withholding_category(
2047+
category_name=category,
2048+
rate=10,
2049+
from_date=self.prev_fy.year_start_date,
2050+
to_date=self.prev_fy.year_end_date,
2051+
account="TDS - _TC",
2052+
cumulative_threshold=30000,
2053+
)
2054+
self.setup_party_with_category("Supplier", supplier, category)
2055+
prev_fy_date = add_days(self.prev_fy.year_end_date, -10)
2056+
2057+
# Previous FY: 3 invoices to cross the 30000 cumulative threshold
2058+
for _ in range(3):
2059+
pi = create_purchase_invoice(supplier=supplier, posting_date=prev_fy_date, set_posting_time=True)
2060+
pi.submit()
2061+
invoices.append(pi)
2062+
2063+
# Third invoice crosses the threshold - 3000 TDS deducted across all three
2064+
self.validate_tax_deduction(invoices[-1], 3000)
2065+
2066+
# Current FY: 10000 invoice - must be Under Withheld, threshold resets
2067+
pi_curr = create_purchase_invoice(supplier=supplier)
2068+
pi_curr.submit()
2069+
invoices.append(pi_curr)
2070+
self.validate_tax_deduction(pi_curr, 0)
2071+
2072+
self.validate_tax_withholding_entries(
2073+
"Purchase Invoice",
2074+
pi_curr.name,
2075+
[
2076+
self.get_tax_withholding_entry(
2077+
tax_withholding_category=category,
2078+
party_type="Supplier",
2079+
party=supplier,
2080+
taxable_doctype="Purchase Invoice",
2081+
taxable_name=pi_curr.name,
2082+
tax_rate=10.0,
2083+
taxable_amount=10000.0,
2084+
withholding_amount=0.0,
2085+
status="Under Withheld",
2086+
withholding_doctype=None,
2087+
withholding_name=None,
2088+
under_withheld_reason=None,
2089+
)
2090+
],
2091+
)
2092+
self.cleanup_invoices(invoices)
2093+
2094+
def test_tax_on_excess_threshold_resets_in_new_fiscal_year(self):
2095+
"""
2096+
For tax-on-excess categories, unused threshold must reset each FY.
2097+
"""
2098+
self.set_previous_fy_and_tax_category()
2099+
invoices = []
2100+
supplier = "Test TDS Supplier3"
2101+
category = "New TDS Category"
2102+
create_tax_withholding_category(
2103+
category_name=category,
2104+
rate=10,
2105+
from_date=self.prev_fy.year_start_date,
2106+
to_date=self.prev_fy.year_end_date,
2107+
account="TDS - _TC",
2108+
cumulative_threshold=30000,
2109+
tax_on_excess_amount=1,
2110+
round_off_tax_amount=1,
2111+
)
2112+
self.setup_party_with_category("Supplier", supplier, category)
2113+
prev_fy_date = add_days(self.prev_fy.year_end_date, -10)
2114+
2115+
for _ in range(2):
2116+
pi = create_purchase_invoice(supplier=supplier, posting_date=prev_fy_date, set_posting_time=True)
2117+
pi.submit()
2118+
invoices.append(pi)
2119+
2120+
pi3 = create_purchase_invoice(
2121+
supplier=supplier, rate=20000, posting_date=prev_fy_date, set_posting_time=True
2122+
)
2123+
pi3.submit()
2124+
invoices.append(pi3)
2125+
2126+
self.validate_tax_deduction(pi3, 1000)
2127+
self.validate_tax_withholding_entries(
2128+
"Purchase Invoice",
2129+
pi3.name,
2130+
[
2131+
self.get_tax_withholding_entry(
2132+
tax_withholding_category=category,
2133+
party_type="Supplier",
2134+
party=supplier,
2135+
taxable_doctype="Purchase Invoice",
2136+
taxable_name=pi3.name,
2137+
tax_rate=10.0,
2138+
taxable_amount=10000.0,
2139+
withholding_amount=0.0,
2140+
status="Settled",
2141+
withholding_doctype="Purchase Invoice",
2142+
withholding_name=pi3.name,
2143+
under_withheld_reason="Threshold Exemption",
2144+
),
2145+
self.get_tax_withholding_entry(
2146+
tax_withholding_category=category,
2147+
party_type="Supplier",
2148+
party=supplier,
2149+
taxable_doctype="Purchase Invoice",
2150+
taxable_name=pi3.name,
2151+
tax_rate=10.0,
2152+
taxable_amount=10000.0,
2153+
withholding_amount=1000.0,
2154+
status="Settled",
2155+
withholding_doctype="Purchase Invoice",
2156+
withholding_name=pi3.name,
2157+
under_withheld_reason=None,
2158+
),
2159+
],
2160+
)
2161+
2162+
# no excess, so no TDS
2163+
pi_curr = create_purchase_invoice(supplier=supplier, rate=30000)
2164+
pi_curr.submit()
2165+
invoices.append(pi_curr)
2166+
self.validate_tax_deduction(pi_curr, 0)
2167+
2168+
self.validate_tax_withholding_entries(
2169+
"Purchase Invoice",
2170+
pi_curr.name,
2171+
[
2172+
self.get_tax_withholding_entry(
2173+
tax_withholding_category=category,
2174+
party_type="Supplier",
2175+
party=supplier,
2176+
taxable_doctype="Purchase Invoice",
2177+
taxable_name=pi_curr.name,
2178+
tax_rate=10.0,
2179+
taxable_amount=30000.0,
2180+
withholding_amount=0.0,
2181+
status="Settled",
2182+
withholding_doctype="Purchase Invoice",
2183+
withholding_name=pi_curr.name,
2184+
under_withheld_reason="Threshold Exemption",
2185+
),
2186+
],
2187+
)
2188+
self.cleanup_invoices(invoices)
2189+
20462190
@ERPNextTestSuite.change_settings("Accounts Settings", {"delete_linked_ledger_entries": 1})
20472191
def test_tds_payment_entry_cancellation(self):
20482192
"""
@@ -3997,7 +4141,7 @@ def create_tax_withholding_category(
39974141
tax_deduction_basis="Net Total",
39984142
):
39994143
if not frappe.db.exists("Tax Withholding Category", category_name):
4000-
frappe.get_doc(
4144+
doc = frappe.get_doc(
40014145
{
40024146
"doctype": "Tax Withholding Category",
40034147
"name": category_name,
@@ -4018,6 +4162,22 @@ def create_tax_withholding_category(
40184162
"accounts": [{"company": "_Test Company", "account": account}],
40194163
}
40204164
).insert()
4165+
else:
4166+
doc = frappe.get_doc("Tax Withholding Category", category_name)
4167+
if not any(getdate(r.from_date) == getdate(from_date) for r in doc.rates):
4168+
doc.append(
4169+
"rates",
4170+
{
4171+
"from_date": from_date,
4172+
"to_date": to_date,
4173+
"tax_withholding_rate": rate,
4174+
"single_threshold": single_threshold,
4175+
"cumulative_threshold": cumulative_threshold,
4176+
},
4177+
)
4178+
doc.save()
4179+
4180+
return doc
40214181

40224182

40234183
def create_lower_deduction_certificate(

erpnext/accounts/doctype/tax_withholding_entry/tax_withholding_entry.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,7 @@ def _base_threshold_query(self, category):
642642
.where(entry.tax_withholding_category == category.name)
643643
.where(entry.company == self.doc.company)
644644
.where(entry.docstatus == 1)
645+
.where(entry.taxable_date.between(category.from_date, category.to_date))
645646
.groupby(entry.status)
646647
)
647648

0 commit comments

Comments
 (0)