From 325c4e3536aaf84be0d7fb9ff9850360b2eeb2bd Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 31 Jan 2025 15:34:50 +0530 Subject: [PATCH 1/2] fix: '0' rate LDC's Invoice net totals should be ignored --- .../tax_withholding_category.py | 42 ++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py index 3215b93a496..06549973242 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -270,7 +270,10 @@ def get_lower_deduction_certificate(company, posting_date, tax_details, pan_no): def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=None): vouchers, voucher_wise_amount = get_invoice_vouchers( - parties, tax_details, inv.company, party_type=party_type + parties, + tax_details, + inv.company, + party_type=party_type, ) payment_entry_vouchers = get_payment_entry_vouchers( @@ -360,11 +363,23 @@ def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"): voucher_wise_amount = [] vouchers = [] + ldcs = frappe.db.get_all( + "Lower Deduction Certificate", + filters={ + "valid_from": [">=", tax_details.from_date], + "valid_upto": ["<=", tax_details.to_date], + "company": company, + "supplier": ["in", parties], + }, + fields=["supplier", "valid_from", "valid_upto", "rate"], + ) + doctype = "Purchase Invoice" if party_type == "Supplier" else "Sales Invoice" field = [ "base_tax_withholding_net_total as base_net_total" if party_type == "Supplier" else "base_net_total", "name", "grand_total", + "posting_date", ] filters = { @@ -383,18 +398,23 @@ def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"): invoices_details = frappe.get_all(doctype, filters=filters, fields=field) for d in invoices_details: - vouchers.append(d.name) - voucher_wise_amount.append( - frappe._dict( - { - "voucher_name": d.name, - "voucher_type": doctype, - "taxable_amount": d.base_net_total, - "grand_total": d.grand_total, - } - ) + d = frappe._dict( + { + "voucher_name": d.name, + "voucher_type": doctype, + "taxable_amount": d.base_net_total, + "grand_total": d.grand_total, + "posting_date": d.posting_date, + } ) + if ldc := [x for x in ldcs if d.posting_date >= x.valid_from and d.posting_date <= x.valid_upto]: + if ldc[0].supplier in parties and ldc[0].rate == 0: + d.update({"taxable_amount": 0}) + + vouchers.append(d.voucher_name) + voucher_wise_amount.append(d) + journal_entries_details = frappe.db.sql( """ SELECT j.name, ja.credit - ja.debit AS amount, ja.reference_type From 0cdd346f8fd2000cba7591d3b03bf0db7b69f158 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 7 Feb 2025 12:18:01 +0530 Subject: [PATCH 2/2] test: ldc @ 0 rate --- .../test_tax_withholding_category.py | 56 +++++++++++++++++-- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py index 109a15a968e..303eeaa72d9 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py @@ -7,7 +7,7 @@ import unittest import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields from frappe.tests import IntegrationTestCase, UnitTestCase -from frappe.utils import add_days, today +from frappe.utils import add_days, add_months, today from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry from erpnext.accounts.utils import get_fiscal_year @@ -676,6 +676,49 @@ class TestTaxWithholdingCategory(IntegrationTestCase): pi2.cancel() pi3.cancel() + def test_ldc_at_0_rate(self): + frappe.db.set_value( + "Supplier", + "Test LDC Supplier", + { + "tax_withholding_category": "Test Service Category", + "pan": "ABCTY1234D", + }, + ) + + fiscal_year = get_fiscal_year(today(), company="_Test Company") + valid_from = fiscal_year[1] + valid_upto = add_months(valid_from, 1) + create_lower_deduction_certificate( + supplier="Test LDC Supplier", + certificate_no="1AE0423AAJ", + tax_withholding_category="Test Service Category", + tax_rate=0, + limit=50000, + valid_from=valid_from, + valid_upto=valid_upto, + ) + + pi1 = create_purchase_invoice( + supplier="Test LDC Supplier", rate=35000, posting_date=valid_from, set_posting_time=True + ) + pi1.submit() + self.assertEqual(pi1.taxes, []) + + pi2 = create_purchase_invoice( + supplier="Test LDC Supplier", + rate=35000, + posting_date=add_days(valid_upto, 1), + set_posting_time=True, + ) + pi2.submit() + self.assertEqual(len(pi2.taxes), 1) + # pi1 net total shouldn't be included as it lies within LDC at rate of '0' + self.assertEqual(pi2.taxes[0].tax_amount, 3500) + + pi1.cancel() + pi2.cancel() + def set_previous_fy_and_tax_category(self): test_company = "_Test Company" category = "Cumulative Threshold TDS" @@ -833,7 +876,8 @@ def create_purchase_invoice(**args): pi = frappe.get_doc( { "doctype": "Purchase Invoice", - "posting_date": today(), + "set_posting_time": args.set_posting_time or False, + "posting_date": args.posting_date or today(), "apply_tds": 0 if args.do_not_apply_tds else 1, "supplier": args.supplier, "company": "_Test Company", @@ -1171,7 +1215,9 @@ def create_tax_withholding_category( ).insert() -def create_lower_deduction_certificate(supplier, tax_withholding_category, tax_rate, certificate_no, limit): +def create_lower_deduction_certificate( + supplier, tax_withholding_category, tax_rate, certificate_no, limit, valid_from=None, valid_upto=None +): fiscal_year = get_fiscal_year(today(), company="_Test Company") if not frappe.db.exists("Lower Deduction Certificate", certificate_no): frappe.get_doc( @@ -1182,8 +1228,8 @@ def create_lower_deduction_certificate(supplier, tax_withholding_category, tax_r "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], + "valid_from": valid_from or fiscal_year[1], + "valid_upto": valid_upto or fiscal_year[2], "rate": tax_rate, "certificate_limit": limit, }