From 534b25c4485079ab4e725c296f31aa65ef9d8f6a Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 13 Feb 2025 13:19:34 +0530 Subject: [PATCH] fix: '0' rate LDC's Invoice net totals should be ignored (backport #45639) (#45783) * fix: '0' rate LDC's Invoice net totals should be ignored (cherry picked from commit 325c4e3536aaf84be0d7fb9ff9850360b2eeb2bd) # Conflicts: # erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py * test: ldc @ 0 rate (cherry picked from commit 0cdd346f8fd2000cba7591d3b03bf0db7b69f158) # Conflicts: # erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py * chore: resolve conflicts * fix: incorrect parameters * fix: ignore 0 rate ldc invoices --------- Co-authored-by: ruthra kumar --- .../tax_withholding_category.py | 58 ++++++++++++++++--- .../test_tax_withholding_category.py | 56 ++++++++++++++++-- 2 files changed, 101 insertions(+), 13 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 2115d44322d..da329324e95 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -236,7 +236,7 @@ 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( + vouchers, voucher_wise_amount, zero_rate_ldc_invoices = get_invoice_vouchers( parties, tax_details, inv.company, party_type=party_type ) @@ -290,7 +290,8 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N # once tds is deducted, not need to add vouchers in the invoice voucher_wise_amount = {} else: - tax_amount = get_tds_amount(ldc, parties, inv, tax_details, vouchers) + taxable_vouchers = list(set(vouchers) - set(zero_rate_ldc_invoices)) + tax_amount = get_tds_amount(ldc, parties, inv, tax_details, taxable_vouchers) elif party_type == "Customer": if tax_deducted: @@ -309,12 +310,33 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"): 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" - ) + field = [ + "name", + "base_tax_withholding_net_total as base_net_total" if party_type == "Supplier" else "base_net_total", + "posting_date", + ] 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 = { "company": company, frappe.scrub(party_type): ["in", parties], @@ -328,11 +350,31 @@ def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"): {"apply_tds": 1, "tax_withholding_category": tax_details.get("tax_withholding_category")} ) - invoices_details = frappe.get_all(doctype, filters=filters, fields=["name", field]) + invoices_details = frappe.get_all(doctype, filters=filters, fields=field) + 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], + "rate": 0, + }, + fields=["name", "supplier", "valid_from", "valid_upto"], + ) + + zero_rate_ldc_invoices = [] for d in invoices_details: vouchers.append(d.name) - voucher_wise_amount.update({d.name: {"amount": d.base_net_total, "voucher_type": doctype}}) + _voucher_detail = {"amount": d.base_net_total, "voucher_type": doctype} + + 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: + _voucher_detail.update({"amount": 0}) + zero_rate_ldc_invoices.append(d.name) + + voucher_wise_amount.update({d.name: _voucher_detail}) journal_entries_details = frappe.db.sql( """ @@ -363,7 +405,7 @@ def get_invoice_vouchers(parties, tax_details, company, party_type="Supplier"): vouchers.append(d.name) voucher_wise_amount.update({d.name: {"amount": d.amount, "voucher_type": "Journal Entry"}}) - return vouchers, voucher_wise_amount + return vouchers, voucher_wise_amount, zero_rate_ldc_invoices def get_payment_entry_vouchers(parties, tax_details, company, party_type="Supplier"): 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 d459b77865c..6a7fc3c43d2 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.utils import FrappeTestCase, change_settings -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 @@ -614,6 +614,49 @@ class TestTaxWithholdingCategory(FrappeTestCase): 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" @@ -771,7 +814,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", @@ -1099,7 +1143,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( @@ -1110,8 +1156,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, }