fix: Tax withholding post LDC limit consumed (#36611)
* fix: Tax withholding post LDC limit consumed * fix: LDC condition check
This commit is contained in:
parent
12a6f3b997
commit
985ff9781b
@ -262,14 +262,20 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N
|
|||||||
if tax_deducted:
|
if tax_deducted:
|
||||||
net_total = inv.tax_withholding_net_total
|
net_total = inv.tax_withholding_net_total
|
||||||
if ldc:
|
if ldc:
|
||||||
tax_amount = get_tds_amount_from_ldc(ldc, parties, tax_details, posting_date, net_total)
|
limit_consumed = get_limit_consumed(ldc, parties)
|
||||||
|
if is_valid_certificate(ldc, posting_date, limit_consumed):
|
||||||
|
tax_amount = get_lower_deduction_amount(
|
||||||
|
net_total, limit_consumed, ldc.certificate_limit, ldc.rate, tax_details
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
tax_amount = net_total * tax_details.rate / 100 if net_total > 0 else 0
|
||||||
else:
|
else:
|
||||||
tax_amount = net_total * tax_details.rate / 100 if net_total > 0 else 0
|
tax_amount = net_total * tax_details.rate / 100 if net_total > 0 else 0
|
||||||
|
|
||||||
# once tds is deducted, not need to add vouchers in the invoice
|
# once tds is deducted, not need to add vouchers in the invoice
|
||||||
voucher_wise_amount = {}
|
voucher_wise_amount = {}
|
||||||
else:
|
else:
|
||||||
tax_amount = get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers)
|
tax_amount = get_tds_amount(ldc, parties, inv, tax_details, vouchers)
|
||||||
|
|
||||||
elif party_type == "Customer":
|
elif party_type == "Customer":
|
||||||
if tax_deducted:
|
if tax_deducted:
|
||||||
@ -416,7 +422,7 @@ def get_deducted_tax(taxable_vouchers, tax_details):
|
|||||||
return sum(entries)
|
return sum(entries)
|
||||||
|
|
||||||
|
|
||||||
def get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers):
|
def get_tds_amount(ldc, parties, inv, tax_details, vouchers):
|
||||||
tds_amount = 0
|
tds_amount = 0
|
||||||
invoice_filters = {"name": ("in", vouchers), "docstatus": 1, "apply_tds": 1}
|
invoice_filters = {"name": ("in", vouchers), "docstatus": 1, "apply_tds": 1}
|
||||||
|
|
||||||
@ -496,15 +502,10 @@ def get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers):
|
|||||||
net_total += inv.tax_withholding_net_total
|
net_total += inv.tax_withholding_net_total
|
||||||
supp_credit_amt = net_total - cumulative_threshold
|
supp_credit_amt = net_total - cumulative_threshold
|
||||||
|
|
||||||
if ldc and is_valid_certificate(
|
if ldc and is_valid_certificate(ldc, inv.get("posting_date") or inv.get("transaction_date"), 0):
|
||||||
ldc.valid_from,
|
tds_amount = get_lower_deduction_amount(
|
||||||
ldc.valid_upto,
|
supp_credit_amt, 0, ldc.certificate_limit, ldc.rate, tax_details
|
||||||
inv.get("posting_date") or inv.get("transaction_date"),
|
)
|
||||||
tax_deducted,
|
|
||||||
inv.tax_withholding_net_total,
|
|
||||||
ldc.certificate_limit,
|
|
||||||
):
|
|
||||||
tds_amount = get_ltds_amount(supp_credit_amt, 0, ldc.certificate_limit, ldc.rate, tax_details)
|
|
||||||
else:
|
else:
|
||||||
tds_amount = supp_credit_amt * tax_details.rate / 100 if supp_credit_amt > 0 else 0
|
tds_amount = supp_credit_amt * tax_details.rate / 100 if supp_credit_amt > 0 else 0
|
||||||
|
|
||||||
@ -582,8 +583,7 @@ def get_invoice_total_without_tcs(inv, tax_details):
|
|||||||
return inv.grand_total - tcs_tax_row_amount
|
return inv.grand_total - tcs_tax_row_amount
|
||||||
|
|
||||||
|
|
||||||
def get_tds_amount_from_ldc(ldc, parties, tax_details, posting_date, net_total):
|
def get_limit_consumed(ldc, parties):
|
||||||
tds_amount = 0
|
|
||||||
limit_consumed = frappe.db.get_value(
|
limit_consumed = frappe.db.get_value(
|
||||||
"Purchase Invoice",
|
"Purchase Invoice",
|
||||||
{
|
{
|
||||||
@ -597,37 +597,29 @@ def get_tds_amount_from_ldc(ldc, parties, tax_details, posting_date, net_total):
|
|||||||
"sum(tax_withholding_net_total)",
|
"sum(tax_withholding_net_total)",
|
||||||
)
|
)
|
||||||
|
|
||||||
if is_valid_certificate(
|
return limit_consumed
|
||||||
ldc.valid_from, ldc.valid_upto, posting_date, limit_consumed, net_total, ldc.certificate_limit
|
|
||||||
|
|
||||||
|
def get_lower_deduction_amount(
|
||||||
|
current_amount, limit_consumed, certificate_limit, rate, tax_details
|
||||||
):
|
):
|
||||||
tds_amount = get_ltds_amount(
|
if certificate_limit - flt(limit_consumed) - flt(current_amount) >= 0:
|
||||||
net_total, limit_consumed, ldc.certificate_limit, ldc.rate, tax_details
|
|
||||||
)
|
|
||||||
|
|
||||||
return tds_amount
|
|
||||||
|
|
||||||
|
|
||||||
def get_ltds_amount(current_amount, deducted_amount, certificate_limit, rate, tax_details):
|
|
||||||
if certificate_limit - flt(deducted_amount) - flt(current_amount) >= 0:
|
|
||||||
return current_amount * rate / 100
|
return current_amount * rate / 100
|
||||||
else:
|
else:
|
||||||
ltds_amount = certificate_limit - flt(deducted_amount)
|
ltds_amount = certificate_limit - flt(limit_consumed)
|
||||||
tds_amount = current_amount - ltds_amount
|
tds_amount = current_amount - ltds_amount
|
||||||
|
|
||||||
return ltds_amount * rate / 100 + tds_amount * tax_details.rate / 100
|
return ltds_amount * rate / 100 + tds_amount * tax_details.rate / 100
|
||||||
|
|
||||||
|
|
||||||
def is_valid_certificate(
|
def is_valid_certificate(ldc, posting_date, limit_consumed):
|
||||||
valid_from, valid_upto, posting_date, deducted_amount, current_amount, certificate_limit
|
available_amount = flt(ldc.certificate_limit) - flt(limit_consumed)
|
||||||
):
|
if (
|
||||||
valid = False
|
getdate(ldc.valid_from) <= getdate(posting_date) <= getdate(ldc.valid_upto)
|
||||||
|
) and available_amount > 0:
|
||||||
|
return True
|
||||||
|
|
||||||
available_amount = flt(certificate_limit) - flt(deducted_amount)
|
return False
|
||||||
|
|
||||||
if (getdate(valid_from) <= getdate(posting_date) <= getdate(valid_upto)) and available_amount > 0:
|
|
||||||
valid = True
|
|
||||||
|
|
||||||
return valid
|
|
||||||
|
|
||||||
|
|
||||||
def normal_round(number):
|
def normal_round(number):
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
|
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
|
||||||
from frappe.utils import today
|
from frappe.utils import today
|
||||||
|
|
||||||
from erpnext.accounts.utils import get_fiscal_year
|
from erpnext.accounts.utils import get_fiscal_year
|
||||||
@ -17,6 +18,7 @@ class TestTaxWithholdingCategory(unittest.TestCase):
|
|||||||
# create relevant supplier, etc
|
# create relevant supplier, etc
|
||||||
create_records()
|
create_records()
|
||||||
create_tax_withholding_category_records()
|
create_tax_withholding_category_records()
|
||||||
|
make_pan_no_field()
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
cancel_invoices()
|
cancel_invoices()
|
||||||
@ -451,6 +453,40 @@ class TestTaxWithholdingCategory(unittest.TestCase):
|
|||||||
pe2.cancel()
|
pe2.cancel()
|
||||||
pe3.cancel()
|
pe3.cancel()
|
||||||
|
|
||||||
|
def test_lower_deduction_certificate_application(self):
|
||||||
|
frappe.db.set_value(
|
||||||
|
"Supplier",
|
||||||
|
"Test LDC Supplier",
|
||||||
|
{
|
||||||
|
"tax_withholding_category": "Test Service Category",
|
||||||
|
"pan": "ABCTY1234D",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
create_lower_deduction_certificate(
|
||||||
|
supplier="Test LDC Supplier",
|
||||||
|
certificate_no="1AE0423AAJ",
|
||||||
|
tax_withholding_category="Test Service Category",
|
||||||
|
tax_rate=2,
|
||||||
|
limit=50000,
|
||||||
|
)
|
||||||
|
|
||||||
|
pi1 = create_purchase_invoice(supplier="Test LDC Supplier", rate=35000)
|
||||||
|
pi1.submit()
|
||||||
|
self.assertEqual(pi1.taxes[0].tax_amount, 700)
|
||||||
|
|
||||||
|
pi2 = create_purchase_invoice(supplier="Test LDC Supplier", rate=35000)
|
||||||
|
pi2.submit()
|
||||||
|
self.assertEqual(pi2.taxes[0].tax_amount, 2300)
|
||||||
|
|
||||||
|
pi3 = create_purchase_invoice(supplier="Test LDC Supplier", rate=35000)
|
||||||
|
pi3.submit()
|
||||||
|
self.assertEqual(pi3.taxes[0].tax_amount, 3500)
|
||||||
|
|
||||||
|
pi1.cancel()
|
||||||
|
pi2.cancel()
|
||||||
|
pi3.cancel()
|
||||||
|
|
||||||
|
|
||||||
def cancel_invoices():
|
def cancel_invoices():
|
||||||
purchase_invoices = frappe.get_all(
|
purchase_invoices = frappe.get_all(
|
||||||
@ -610,6 +646,7 @@ def create_records():
|
|||||||
"Test TDS Supplier6",
|
"Test TDS Supplier6",
|
||||||
"Test TDS Supplier7",
|
"Test TDS Supplier7",
|
||||||
"Test TDS Supplier8",
|
"Test TDS Supplier8",
|
||||||
|
"Test LDC Supplier",
|
||||||
]:
|
]:
|
||||||
if frappe.db.exists("Supplier", name):
|
if frappe.db.exists("Supplier", name):
|
||||||
continue
|
continue
|
||||||
@ -806,3 +843,39 @@ def create_tax_withholding_category(
|
|||||||
"accounts": [{"company": "_Test Company", "account": account}],
|
"accounts": [{"company": "_Test Company", "account": account}],
|
||||||
}
|
}
|
||||||
).insert()
|
).insert()
|
||||||
|
|
||||||
|
|
||||||
|
def create_lower_deduction_certificate(
|
||||||
|
supplier, tax_withholding_category, tax_rate, certificate_no, limit
|
||||||
|
):
|
||||||
|
fiscal_year = get_fiscal_year(today(), company="_Test Company")
|
||||||
|
if not frappe.db.exists("Lower Deduction Certificate", certificate_no):
|
||||||
|
frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Lower Deduction Certificate",
|
||||||
|
"company": "_Test Company",
|
||||||
|
"supplier": supplier,
|
||||||
|
"certificate_no": certificate_no,
|
||||||
|
"tax_withholding_category": tax_withholding_category,
|
||||||
|
"fiscal_year": fiscal_year[0],
|
||||||
|
"valid_from": fiscal_year[1],
|
||||||
|
"valid_upto": fiscal_year[2],
|
||||||
|
"rate": tax_rate,
|
||||||
|
"certificate_limit": limit,
|
||||||
|
}
|
||||||
|
).insert()
|
||||||
|
|
||||||
|
|
||||||
|
def make_pan_no_field():
|
||||||
|
pan_field = {
|
||||||
|
"Supplier": [
|
||||||
|
{
|
||||||
|
"fieldname": "pan",
|
||||||
|
"label": "PAN",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"translatable": 0,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
create_custom_fields(pan_field, update=1)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user