From 5e10e103291f5c70fee3647503ba858c84348f3c Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 31 Aug 2021 18:23:28 +0530 Subject: [PATCH 1/8] feat: Validity dates in Tax Withholding Rates --- .../tax_withholding_category.py | 111 ++++---- .../test_tax_withholding_category.py | 17 +- .../tax_withholding_rate.json | 256 +++++------------- erpnext/patches.txt | 3 +- ...pdate_dates_in_tax_withholding_category.py | 22 ++ 5 files changed, 159 insertions(+), 250 deletions(-) create mode 100644 erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py 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 0cb872c4b81..c871af94289 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -10,7 +10,24 @@ from frappe.utils import flt, getdate, cint from erpnext.accounts.utils import get_fiscal_year class TaxWithholdingCategory(Document): - pass + def validate(self): + self.validate_dates() + self.validate_thresholds() + + def validate_dates(self): + last_date = None + for d in self.get('rates'): + if getdate(d.from_date) >= getdate(d.to_date): + frappe.throw(_("Row #{0}: From Date cannot be before To Date").format(d.idx)) + + # validate overlapping of dates + if last_date and getdate(r.to_date) < getdate(last_date): + frappe.throw(_("Row #{0}: Dates overlapping with other row").format(d.idx)) + + def validate_thresholds(self): + for d in self.get('rates'): + if d.cumulative_threshold and d.cumulative_threshold < d.single_threshold: + frappe.throw(_("Row #{0}: Cumulative threshold cannot be less than Single Transaction threshold").format(d.idx)) def get_party_details(inv): party_type, party = '', '' @@ -49,8 +66,8 @@ def get_party_tax_withholding_details(inv, tax_withholding_category=None): if not parties: parties.append(party) - fiscal_year = get_fiscal_year(inv.get('posting_date') or inv.get('transaction_date'), company=inv.company) - tax_details = get_tax_withholding_details(tax_withholding_category, fiscal_year[0], inv.company) + posting_date = inv.get('posting_date') or inv.get('transaction_date') + tax_details = get_tax_withholding_details(tax_withholding_category, posting_date, inv.company) if not tax_details: frappe.throw(_('Please set associated account in Tax Withholding Category {0} against Company {1}') @@ -64,7 +81,7 @@ def get_party_tax_withholding_details(inv, tax_withholding_category=None): tax_amount, tax_deducted = get_tax_amount( party_type, parties, inv, tax_details, - fiscal_year, pan_no + posting_date, pan_no ) if party_type == 'Supplier': @@ -74,16 +91,18 @@ def get_party_tax_withholding_details(inv, tax_withholding_category=None): return tax_row -def get_tax_withholding_details(tax_withholding_category, fiscal_year, company): +def get_tax_withholding_details(tax_withholding_category, posting_date, company): tax_withholding = frappe.get_doc("Tax Withholding Category", tax_withholding_category) - tax_rate_detail = get_tax_withholding_rates(tax_withholding, fiscal_year) + tax_rate_detail = get_tax_withholding_rates(tax_withholding, posting_date) for account_detail in tax_withholding.accounts: if company == account_detail.company: return frappe._dict({ "account_head": account_detail.account, "rate": tax_rate_detail.tax_withholding_rate, + "from_date": tax_rate_detail.from_date, + "to_date": tax_rate_detail.to_date, "threshold": tax_rate_detail.single_threshold, "cumulative_threshold": tax_rate_detail.cumulative_threshold, "description": tax_withholding.category_name if tax_withholding.category_name else tax_withholding_category, @@ -92,13 +111,13 @@ def get_tax_withholding_details(tax_withholding_category, fiscal_year, company): "round_off_tax_amount": tax_withholding.round_off_tax_amount }) -def get_tax_withholding_rates(tax_withholding, fiscal_year): +def get_tax_withholding_rates(tax_withholding, posting_date): # returns the row that matches with the fiscal year from posting date for rate in tax_withholding.rates: - if rate.fiscal_year == fiscal_year: + if getdate(rate.from_date) <= getdate(posting_date) <= getdate(rate.to_date): return rate - frappe.throw(_("No Tax Withholding data found for the current Fiscal Year.")) + frappe.throw(_("No Tax Withholding data found for the current posting date.")) def get_tax_row_for_tcs(inv, tax_details, tax_amount, tax_deducted): row = { @@ -140,38 +159,38 @@ def get_tax_row_for_tds(tax_details, tax_amount): "account_head": tax_details.account_head } -def get_lower_deduction_certificate(fiscal_year, pan_no): - ldc_name = frappe.db.get_value('Lower Deduction Certificate', { 'pan_no': pan_no, 'fiscal_year': fiscal_year }, 'name') +def get_lower_deduction_certificate(tax_details, pan_no): + ldc_name = frappe.db.get_value('Lower Deduction Certificate', + { + 'pan_no': pan_no, + 'valid_from': ('>=', tax_details.from_date), + 'valid_upto': ('<=', tax_details.to_date) + }, 'name') + if ldc_name: return frappe.get_doc('Lower Deduction Certificate', ldc_name) -def get_tax_amount(party_type, parties, inv, tax_details, fiscal_year_details, pan_no=None): - fiscal_year = fiscal_year_details[0] - - - vouchers = get_invoice_vouchers(parties, fiscal_year, inv.company, party_type=party_type) - advance_vouchers = get_advance_vouchers(parties, fiscal_year, inv.company, party_type=party_type) +def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=None): + vouchers = get_invoice_vouchers(parties, tax_details, inv.company, party_type=party_type) + advance_vouchers = get_advance_vouchers(parties, company=inv.company, from_date=tax_details.from_date, + to_date=tax_details.to_date, party_type=party_type) taxable_vouchers = vouchers + advance_vouchers tax_deducted = 0 if taxable_vouchers: - tax_deducted = get_deducted_tax(taxable_vouchers, fiscal_year, tax_details) + tax_deducted = get_deducted_tax(taxable_vouchers, tax_details) tax_amount = 0 - posting_date = inv.get('posting_date') or inv.get('transaction_date') if party_type == 'Supplier': - ldc = get_lower_deduction_certificate(fiscal_year, pan_no) + ldc = get_lower_deduction_certificate(tax_details, pan_no) if tax_deducted: net_total = inv.net_total if ldc: - tax_amount = get_tds_amount_from_ldc(ldc, parties, fiscal_year, pan_no, tax_details, posting_date, net_total) + tax_amount = get_tds_amount_from_ldc(ldc, parties, pan_no, tax_details, posting_date, net_total) else: tax_amount = net_total * tax_details.rate / 100 if net_total > 0 else 0 else: - tax_amount = get_tds_amount( - ldc, parties, inv, tax_details, - fiscal_year_details, tax_deducted, vouchers - ) + tax_amount = get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers) elif party_type == 'Customer': if tax_deducted: @@ -180,14 +199,11 @@ def get_tax_amount(party_type, parties, inv, tax_details, fiscal_year_details, p else: # if no TCS has been charged in FY, # then chargeable value is "prev invoices + advances" value which cross the threshold - tax_amount = get_tcs_amount( - parties, inv, tax_details, - fiscal_year_details, vouchers, advance_vouchers - ) + tax_amount = get_tcs_amount(parties, inv, tax_details, vouchers, advance_vouchers) return tax_amount, tax_deducted -def get_invoice_vouchers(parties, fiscal_year, company, party_type='Supplier'): +def get_invoice_vouchers(parties, tax_details, company, party_type='Supplier'): dr_or_cr = 'credit' if party_type == 'Supplier' else 'debit' filters = { @@ -195,14 +211,14 @@ def get_invoice_vouchers(parties, fiscal_year, company, party_type='Supplier'): 'company': company, 'party_type': party_type, 'party': ['in', parties], - 'fiscal_year': fiscal_year, + 'posting_date': ['between', (tax_details.from_date, tax_details.to_date)], 'is_opening': 'No', 'is_cancelled': 0 } return frappe.get_all('GL Entry', filters=filters, distinct=1, pluck="voucher_no") or [""] -def get_advance_vouchers(parties, fiscal_year=None, company=None, from_date=None, to_date=None, party_type='Supplier'): +def get_advance_vouchers(parties, company=None, from_date=None, to_date=None, party_type='Supplier'): # for advance vouchers, debit and credit is reversed dr_or_cr = 'debit' if party_type == 'Supplier' else 'credit' @@ -215,8 +231,6 @@ def get_advance_vouchers(parties, fiscal_year=None, company=None, from_date=None 'against_voucher': ['is', 'not set'] } - if fiscal_year: - filters['fiscal_year'] = fiscal_year if company: filters['company'] = company if from_date and to_date: @@ -224,20 +238,21 @@ def get_advance_vouchers(parties, fiscal_year=None, company=None, from_date=None return frappe.get_all('GL Entry', filters=filters, distinct=1, pluck='voucher_no') or [""] -def get_deducted_tax(taxable_vouchers, fiscal_year, tax_details): +def get_deducted_tax(taxable_vouchers, tax_details): # check if TDS / TCS account is already charged on taxable vouchers filters = { 'is_cancelled': 0, 'credit': ['>', 0], - 'fiscal_year': fiscal_year, + 'posting_date': ['between', (tax_details.from_date, tax_details.to_date)], 'account': tax_details.account_head, 'voucher_no': ['in', taxable_vouchers], } - field = "sum(credit)" + field = "credit" - return frappe.db.get_value('GL Entry', filters, field) or 0.0 + entries = frappe.db.get_all('GL Entry', filters, pluck=field) + return sum(entries) -def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_deducted, vouchers): +def get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers): tds_amount = 0 invoice_filters = { 'name': ('in', vouchers), @@ -261,7 +276,7 @@ def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_dedu supp_credit_amt += supp_jv_credit_amt supp_credit_amt += inv.net_total - debit_note_amount = get_debit_note_amount(parties, fiscal_year_details, inv.company) + debit_note_amount = get_debit_note_amount(parties, tax_details.from_date, tax_details.to_date, inv.company) supp_credit_amt -= debit_note_amount threshold = tax_details.get('threshold', 0) @@ -289,9 +304,8 @@ def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_dedu return tds_amount -def get_tcs_amount(parties, inv, tax_details, fiscal_year_details, vouchers, adv_vouchers): +def get_tcs_amount(parties, inv, tax_details, vouchers, adv_vouchers): tcs_amount = 0 - fiscal_year, _, _ = fiscal_year_details # sum of debit entries made from sales invoices invoiced_amt = frappe.db.get_value('GL Entry', { @@ -310,14 +324,14 @@ def get_tcs_amount(parties, inv, tax_details, fiscal_year_details, vouchers, adv }, 'sum(credit)') or 0.0 # sum of credit entries made from sales invoice - credit_note_amt = frappe.db.get_value('GL Entry', { + credit_note_amt = sum(frappe.db.get_all('GL Entry', { 'is_cancelled': 0, 'credit': ['>', 0], 'party': ['in', parties], - 'fiscal_year': fiscal_year, + 'posting_date': ['between', (tax_details.from_date, tax_details.to_date)], 'company': inv.company, 'voucher_type': 'Sales Invoice', - }, 'sum(credit)') or 0.0 + }, pluck='credit')) cumulative_threshold = tax_details.get('cumulative_threshold', 0) @@ -336,7 +350,7 @@ def get_invoice_total_without_tcs(inv, tax_details): return inv.grand_total - tcs_tax_row_amount -def get_tds_amount_from_ldc(ldc, parties, fiscal_year, pan_no, tax_details, posting_date, net_total): +def get_tds_amount_from_ldc(ldc, parties, pan_no, tax_details, posting_date, net_total): tds_amount = 0 limit_consumed = frappe.db.get_value('Purchase Invoice', { 'supplier': ('in', parties), @@ -353,14 +367,13 @@ def get_tds_amount_from_ldc(ldc, parties, fiscal_year, pan_no, tax_details, post return tds_amount -def get_debit_note_amount(suppliers, fiscal_year_details, company=None): - _, year_start_date, year_end_date = fiscal_year_details +def get_debit_note_amount(suppliers, from_date, to_date, company=None): filters = { 'supplier': ['in', suppliers], 'is_return': 1, 'docstatus': 1, - 'posting_date': ['between', (year_start_date, year_end_date)] + 'posting_date': ['between', (from_date, to_date)] } fields = ['abs(sum(net_total)) as net_total'] 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 0f921db678d..138aaec6ab0 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 @@ -312,16 +312,16 @@ def create_records(): }).insert() def create_tax_with_holding_category(): - fiscal_year = get_fiscal_year(today(), company="_Test Company")[0] - - # Cummulative thresold + fiscal_year = get_fiscal_year(today(), company="_Test Company") + # Cumulative threshold if not frappe.db.exists("Tax Withholding Category", "Cumulative Threshold TDS"): frappe.get_doc({ "doctype": "Tax Withholding Category", "name": "Cumulative Threshold TDS", "category_name": "10% TDS", "rates": [{ - 'fiscal_year': fiscal_year, + 'from_date': fiscal_year[1], + 'to_date': fiscal_year[2], 'tax_withholding_rate': 10, 'single_threshold': 0, 'cumulative_threshold': 30000.00 @@ -338,7 +338,8 @@ def create_tax_with_holding_category(): "name": "Cumulative Threshold TCS", "category_name": "10% TCS", "rates": [{ - 'fiscal_year': fiscal_year, + 'from_date': fiscal_year[1], + 'to_date': fiscal_year[2], 'tax_withholding_rate': 10, 'single_threshold': 0, 'cumulative_threshold': 30000.00 @@ -356,7 +357,8 @@ def create_tax_with_holding_category(): "name": "Single Threshold TDS", "category_name": "10% TDS", "rates": [{ - 'fiscal_year': fiscal_year, + 'from_date': fiscal_year[1], + 'to_date': fiscal_year[2], 'tax_withholding_rate': 10, 'single_threshold': 20000.00, 'cumulative_threshold': 0 @@ -376,7 +378,8 @@ def create_tax_with_holding_category(): "consider_party_ledger_amount": 1, "tax_on_excess_amount": 1, "rates": [{ - 'fiscal_year': fiscal_year, + 'from_date': fiscal_year[1], + 'to_date': fiscal_year[2], 'tax_withholding_rate': 10, 'single_threshold': 0, 'cumulative_threshold': 30000 diff --git a/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.json b/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.json index 1e8194af6e4..d2c505c6300 100644 --- a/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.json +++ b/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.json @@ -1,202 +1,72 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2018-07-17 16:53:13.716665", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "creation": "2018-07-17 16:53:13.716665", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "from_date", + "to_date", + "tax_withholding_rate", + "column_break_3", + "single_threshold", + "cumulative_threshold" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 2, - "fieldname": "fiscal_year", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Fiscal Year", - "length": 0, - "no_copy": 0, - "options": "Fiscal Year", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "columns": 1, + "fieldname": "tax_withholding_rate", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Tax Withholding Rate", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 2, - "fieldname": "tax_withholding_rate", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Tax Withholding Rate", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_3", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "columns": 2, + "fieldname": "single_threshold", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Single Transaction Threshold" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 3, - "fieldname": "single_threshold", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Single Transaction Threshold", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "columns": 3, + "fieldname": "cumulative_threshold", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Cumulative Transaction Threshold" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 3, - "fieldname": "cumulative_threshold", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Cumulative Transaction Threshold", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "columns": 2, + "fieldname": "from_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "From Date", + "reqd": 1 + }, + { + "columns": 2, + "fieldname": "to_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "To Date", + "reqd": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2018-07-17 17:13:09.819580", - "modified_by": "Administrator", - "module": "Accounts", - "name": "Tax Withholding Rate", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-08-31 11:42:12.213977", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Tax Withholding Rate", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 05c385b6bac..ae83d5eb961 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -300,4 +300,5 @@ erpnext.patches.v13_0.reset_clearance_date_for_intracompany_payment_entries erpnext.patches.v13_0.einvoicing_deprecation_warning erpnext.patches.v14_0.delete_einvoicing_doctypes erpnext.patches.v13_0.set_operation_time_based_on_operating_cost -erpnext.patches.v13_0.validate_options_for_data_field \ No newline at end of file +erpnext.patches.v13_0.validate_options_for_data_field +erpnext.patches.v13_0.update_dates_in_tax_withholding_category \ No newline at end of file diff --git a/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py b/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py new file mode 100644 index 00000000000..2563d8a8c4b --- /dev/null +++ b/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py @@ -0,0 +1,22 @@ +# Copyright (c) 2021, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +import frappe +from erpnext.accounts.utils import get_fiscal_year + +def execute(): + frappe.reload_doc('accounts', 'doctype', 'Tax Withholding Rate') + tds_category_rates = frappe.get_all('Tax Withholding Rate', fields=['name', 'fiscal_year']) + + fiscal_year_map = {} + for rate in tds_category_rates: + if not fiscal_year_map.get(rate.fiscal_year): + fiscal_year_map[rate.fiscal_year] = get_fiscal_year(fiscal_year=rate.fiscal_year) + + from_date = fiscal_year_map.get(rate.fiscal_year)[1] + to_date = fiscal_year_map.get(rate.fiscal_year)[2] + + frappe.db.set_value('Tax Withholding Rate', rate.name, { + 'from_date': from_date, + 'to_date': to_date + }) \ No newline at end of file From d06221ad7a0c622d3b2c9e8992c97af28f38f79f Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 1 Sep 2021 10:05:10 +0530 Subject: [PATCH 2/8] fix: Advance TDS test case --- .../accounts/doctype/purchase_invoice/test_purchase_invoice.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 37ff52c6109..88acebcf494 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -1226,7 +1226,8 @@ def update_tax_witholding_category(company, account, date): {'parent': 'TDS - 194 - Dividends - Individual', 'fiscal_year': fiscal_year[0]}): tds_category = frappe.get_doc('Tax Withholding Category', 'TDS - 194 - Dividends - Individual') tds_category.append('rates', { - 'fiscal_year': fiscal_year[0], + 'from_date': fiscal_year[1], + 'to_date': fiscal_year[2], 'tax_withholding_rate': 10, 'single_threshold': 2500, 'cumulative_threshold': 0 From b6d0b17ed6930b43157c51c0e0fec8457881f7bb Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 1 Sep 2021 10:11:18 +0530 Subject: [PATCH 3/8] fix: Linting and patch fixes --- .../tax_withholding_category.py | 2 +- ...pdate_dates_in_tax_withholding_category.py | 24 ++++++++++--------- 2 files changed, 14 insertions(+), 12 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 c871af94289..06b8df1dfe8 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -21,7 +21,7 @@ class TaxWithholdingCategory(Document): frappe.throw(_("Row #{0}: From Date cannot be before To Date").format(d.idx)) # validate overlapping of dates - if last_date and getdate(r.to_date) < getdate(last_date): + if last_date and getdate(d.to_date) < getdate(last_date): frappe.throw(_("Row #{0}: Dates overlapping with other row").format(d.idx)) def validate_thresholds(self): diff --git a/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py b/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py index 2563d8a8c4b..33c49428533 100644 --- a/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py +++ b/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py @@ -6,17 +6,19 @@ from erpnext.accounts.utils import get_fiscal_year def execute(): frappe.reload_doc('accounts', 'doctype', 'Tax Withholding Rate') - tds_category_rates = frappe.get_all('Tax Withholding Rate', fields=['name', 'fiscal_year']) - fiscal_year_map = {} - for rate in tds_category_rates: - if not fiscal_year_map.get(rate.fiscal_year): - fiscal_year_map[rate.fiscal_year] = get_fiscal_year(fiscal_year=rate.fiscal_year) + if frappe.db.has_column('Tax Withholding Rate', 'fiscal_year'): + tds_category_rates = frappe.get_all('Tax Withholding Rate', fields=['name', 'fiscal_year']) - from_date = fiscal_year_map.get(rate.fiscal_year)[1] - to_date = fiscal_year_map.get(rate.fiscal_year)[2] + fiscal_year_map = {} + for rate in tds_category_rates: + if not fiscal_year_map.get(rate.fiscal_year): + fiscal_year_map[rate.fiscal_year] = get_fiscal_year(fiscal_year=rate.fiscal_year) - frappe.db.set_value('Tax Withholding Rate', rate.name, { - 'from_date': from_date, - 'to_date': to_date - }) \ No newline at end of file + from_date = fiscal_year_map.get(rate.fiscal_year)[1] + to_date = fiscal_year_map.get(rate.fiscal_year)[2] + + frappe.db.set_value('Tax Withholding Rate', rate.name, { + 'from_date': from_date, + 'to_date': to_date + }) \ No newline at end of file From d5a736d11e5096f2861c3e5e6267584488df6d7d Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 1 Sep 2021 21:15:24 +0530 Subject: [PATCH 4/8] test: Update test case --- .../accounts/doctype/purchase_invoice/test_purchase_invoice.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 88acebcf494..06f4fdb799c 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -1223,7 +1223,8 @@ def update_tax_witholding_category(company, account, date): fiscal_year = get_fiscal_year(date=date, company=company) if not frappe.db.get_value('Tax Withholding Rate', - {'parent': 'TDS - 194 - Dividends - Individual', 'fiscal_year': fiscal_year[0]}): + {'parent': 'TDS - 194 - Dividends - Individual', 'from_date': ('>=', fiscal_year[1]), + 'to_date': ('<=', fiscal_year[2])}): tds_category = frappe.get_doc('Tax Withholding Category', 'TDS - 194 - Dividends - Individual') tds_category.append('rates', { 'from_date': fiscal_year[1], From 092d41ecda917c68db8329c824ca68ced82db195 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 3 Sep 2021 20:04:18 +0530 Subject: [PATCH 5/8] fix: Debug CI --- .../accounts/doctype/purchase_invoice/test_purchase_invoice.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 51f58b74027..a7298d5e308 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -1230,6 +1230,7 @@ def update_tax_witholding_category(company, account, date): from erpnext.accounts.utils import get_fiscal_year fiscal_year = get_fiscal_year(date=date, company=company) + print(fiscal_year[0], fiscal_year[1], fiscal_year[2], "$#$#$#") if not frappe.db.get_value('Tax Withholding Rate', {'parent': 'TDS - 194 - Dividends - Individual', 'from_date': ('>=', fiscal_year[1]), From 51d9572fe72902593e363a19bc52967d65f56b88 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 5 Sep 2021 17:56:12 +0530 Subject: [PATCH 6/8] fix: Hardcode fiscal year and posting date --- .../doctype/fiscal_year/fiscal_year_dashboard.py | 2 +- .../doctype/purchase_invoice/test_purchase_invoice.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/fiscal_year/fiscal_year_dashboard.py b/erpnext/accounts/doctype/fiscal_year/fiscal_year_dashboard.py index 58480df1190..92e8a426cff 100644 --- a/erpnext/accounts/doctype/fiscal_year/fiscal_year_dashboard.py +++ b/erpnext/accounts/doctype/fiscal_year/fiscal_year_dashboard.py @@ -13,7 +13,7 @@ def get_data(): }, { 'label': _('References'), - 'items': ['Period Closing Voucher', 'Tax Withholding Category'] + 'items': ['Period Closing Voucher'] }, { 'label': _('Target Details'), diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index a7298d5e308..2d6ab7b2935 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -1151,10 +1151,11 @@ class TestPurchaseInvoice(unittest.TestCase): tax_withholding_category = 'TDS - 194 - Dividends - Individual') # Update tax withholding category with current fiscal year and rate details - update_tax_witholding_category('_Test Company', 'TDS Payable - _TC', nowdate()) + update_tax_witholding_category('_Test Company', 'TDS Payable - _TC') # Create Purchase Order with TDS applied - po = create_purchase_order(do_not_save=1, supplier=supplier.name, rate=3000, item='_Test Non Stock Item') + po = create_purchase_order(do_not_save=1, supplier=supplier.name, rate=3000, item='_Test Non Stock Item', + posting_date='2021-09-15') po.apply_tds = 1 po.tax_withholding_category = 'TDS - 194 - Dividends - Individual' po.save() @@ -1226,11 +1227,10 @@ def check_gl_entries(doc, voucher_no, expected_gle, posting_date): doc.assertEqual(expected_gle[i][2], gle.credit) doc.assertEqual(getdate(expected_gle[i][3]), gle.posting_date) -def update_tax_witholding_category(company, account, date): +def update_tax_witholding_category(company, account): from erpnext.accounts.utils import get_fiscal_year - fiscal_year = get_fiscal_year(date=date, company=company) - print(fiscal_year[0], fiscal_year[1], fiscal_year[2], "$#$#$#") + fiscal_year = get_fiscal_year(fiscal_year='_Test Fiscal Year 2021') if not frappe.db.get_value('Tax Withholding Rate', {'parent': 'TDS - 194 - Dividends - Individual', 'from_date': ('>=', fiscal_year[1]), From c33bbd4f399b95ab23cc1a621086a366d7be7435 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 9 Sep 2021 11:13:29 +0530 Subject: [PATCH 7/8] fix: Test Case --- .../doctype/purchase_invoice/test_purchase_invoice.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 2d6ab7b2935..5cbeb562326 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -1230,12 +1230,14 @@ def check_gl_entries(doc, voucher_no, expected_gle, posting_date): def update_tax_witholding_category(company, account): from erpnext.accounts.utils import get_fiscal_year - fiscal_year = get_fiscal_year(fiscal_year='_Test Fiscal Year 2021') + fiscal_year = get_fiscal_year(fiscal_year='2021') if not frappe.db.get_value('Tax Withholding Rate', {'parent': 'TDS - 194 - Dividends - Individual', 'from_date': ('>=', fiscal_year[1]), 'to_date': ('<=', fiscal_year[2])}): tds_category = frappe.get_doc('Tax Withholding Category', 'TDS - 194 - Dividends - Individual') + tds_category.set('rates', []) + tds_category.append('rates', { 'from_date': fiscal_year[1], 'to_date': fiscal_year[2], From e7e2ce127116a9b0152d497ee9d11fbf9fff19f9 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 9 Sep 2021 11:36:57 +0530 Subject: [PATCH 8/8] fix: Linting Issues --- .../tax_withholding_category/tax_withholding_category.py | 6 ++---- .../v13_0/update_dates_in_tax_withholding_category.py | 2 ++ 2 files changed, 4 insertions(+), 4 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 33b7e475e51..fa4ea218e90 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -9,8 +9,6 @@ from frappe import _ from frappe.model.document import Document from frappe.utils import cint, getdate -from erpnext.accounts.utils import get_fiscal_year - class TaxWithholdingCategory(Document): def validate(self): @@ -163,9 +161,9 @@ def get_tax_row_for_tds(tax_details, tax_amount): } def get_lower_deduction_certificate(tax_details, pan_no): - ldc_name = frappe.db.get_value('Lower Deduction Certificate', + ldc_name = frappe.db.get_value('Lower Deduction Certificate', { - 'pan_no': pan_no, + 'pan_no': pan_no, 'valid_from': ('>=', tax_details.from_date), 'valid_upto': ('<=', tax_details.to_date) }, 'name') diff --git a/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py b/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py index 33c49428533..2af7f954128 100644 --- a/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py +++ b/erpnext/patches/v13_0/update_dates_in_tax_withholding_category.py @@ -2,8 +2,10 @@ # License: GNU General Public License v3. See license.txt import frappe + from erpnext.accounts.utils import get_fiscal_year + def execute(): frappe.reload_doc('accounts', 'doctype', 'Tax Withholding Rate')