diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 751b46f4b35..94b76b12ce7 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -9,15 +9,16 @@ jobs: name: linters runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python 3.10 - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: '3.10' + cache: pip - name: Install and Run Pre-commit - uses: pre-commit/action@v2.0.3 + uses: pre-commit/action@v3.0.0 - name: Download Semgrep rules run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 56bcb22c9bb..69c40d56227 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,5 @@ exclude: 'node_modules|.git' -default_stages: [commit] +default_stages: [pre-commit] fail_fast: false diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py index 3c03005b1cb..3649a41963f 100644 --- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py +++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py @@ -4,6 +4,7 @@ import frappe from frappe import _ +from frappe.utils import getdate def execute(filters=None): @@ -33,6 +34,7 @@ def execute(filters=None): def validate_filters(filters): """Validate if dates are properly set""" + filters = frappe._dict(filters or {}) if filters.from_date > filters.to_date: frappe.throw(_("From Date must be before To Date")) @@ -68,7 +70,7 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_ if not tax_withholding_category: tax_withholding_category = party_map.get(party, {}).get("tax_withholding_category") - rate = tax_rate_map.get(tax_withholding_category) + rate = get_tax_withholding_rates(tax_rate_map.get(tax_withholding_category, []), posting_date) if net_total_map.get((voucher_type, name)): if voucher_type == "Journal Entry" and tax_amount and rate: # back calcalute total amount from rate and tax_amount @@ -435,12 +437,22 @@ def get_doc_info(vouchers, doctype, tax_category_map, net_total_map=None): def get_tax_rate_map(filters): rate_map = frappe.get_all( "Tax Withholding Rate", - filters={ - "from_date": ("<=", filters.get("from_date")), - "to_date": (">=", filters.get("to_date")), - }, - fields=["parent", "tax_withholding_rate"], - as_list=1, + filters={"from_date": ("<=", filters.to_date), "to_date": (">=", filters.from_date)}, + fields=["parent", "tax_withholding_rate", "from_date", "to_date"], ) - return frappe._dict(rate_map) + rate_list = frappe._dict() + + for rate in rate_map: + rate_list.setdefault(rate.parent, []).append(frappe._dict(rate)) + + return rate_list + + +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: + if getdate(rate.from_date) <= getdate(posting_date) <= getdate(rate.to_date): + return rate.tax_withholding_rate + + return 0 diff --git a/erpnext/accounts/report/tds_payable_monthly/test_tds_payable_monthly.py b/erpnext/accounts/report/tds_payable_monthly/test_tds_payable_monthly.py index 742d2f37c45..91461e517dc 100644 --- a/erpnext/accounts/report/tds_payable_monthly/test_tds_payable_monthly.py +++ b/erpnext/accounts/report/tds_payable_monthly/test_tds_payable_monthly.py @@ -3,7 +3,7 @@ import frappe from frappe.tests.utils import FrappeTestCase -from frappe.utils import today +from frappe.utils import add_to_date, today from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice @@ -60,6 +60,56 @@ class TestTdsPayableMonthly(AccountsTestMixin, FrappeTestCase): ] self.check_expected_values(result, expected_values) + def test_date_filters_in_multiple_tax_withholding_rules(self): + create_tax_category("TDS - 3", rate=10, account="TDS - _TC", cumulative_threshold=1) + # insert new rate in same fiscal year + fiscal_year = get_fiscal_year(today(), company="_Test Company") + mid_year = add_to_date(fiscal_year[1], months=6) + tds_doc = frappe.get_doc("Tax Withholding Category", "TDS - 3") + tds_doc.rates[0].to_date = mid_year + tds_doc.append( + "rates", + { + "tax_withholding_rate": 20, + "from_date": add_to_date(mid_year, days=1), + "to_date": fiscal_year[2], + "single_threshold": 1, + "cumulative_threshold": 1, + }, + ) + + tds_doc.save() + + inv_1 = make_purchase_invoice(rate=1000, do_not_submit=True) + inv_1.apply_tds = 1 + inv_1.tax_withholding_category = "TDS - 3" + inv_1.submit() + + inv_2 = make_purchase_invoice( + rate=1000, do_not_submit=True, posting_date=add_to_date(mid_year, days=1), do_not_save=True + ) + inv_2.set_posting_time = 1 + + inv_1.apply_tds = 1 + inv_2.tax_withholding_category = "TDS - 3" + inv_2.save() + inv_2.submit() + + result = execute( + frappe._dict( + company="_Test Company", + party_type="Supplier", + from_date=fiscal_year[1], + to_date=fiscal_year[2], + ) + )[1] + + expected_values = [ + [inv_1.name, "TDS - 3", 10.0, 5000, 500, 4500], + [inv_2.name, "TDS - 3", 20.0, 5000, 1000, 4000], + ] + self.check_expected_values(result, expected_values) + def check_expected_values(self, result, expected_values): for i in range(len(result)): voucher = frappe._dict(result[i]) diff --git a/erpnext/public/js/utils/dimension_tree_filter.js b/erpnext/public/js/utils/dimension_tree_filter.js index 36c0f1b51ae..68bf11de5d8 100644 --- a/erpnext/public/js/utils/dimension_tree_filter.js +++ b/erpnext/public/js/utils/dimension_tree_filter.js @@ -77,35 +77,34 @@ erpnext.accounts.dimensions = { }, update_dimension(frm, doctype) { - if (this.accounting_dimensions) { - this.accounting_dimensions.forEach((dimension) => { - if (frm.is_new()) { - if ( - frm.doc.company && - Object.keys(this.default_dimensions || {}).length > 0 && - this.default_dimensions[frm.doc.company] - ) { - let default_dimension = - this.default_dimensions[frm.doc.company][dimension["fieldname"]]; + if ( + !this.accounting_dimensions || + !frm.is_new() || + !frm.doc.company || + !this.default_dimensions?.[frm.doc.company] + ) + return; - if (default_dimension) { - if (frappe.meta.has_field(doctype, dimension["fieldname"])) { - frm.set_value(dimension["fieldname"], default_dimension); - } - - $.each(frm.doc.items || frm.doc.accounts || [], function (i, row) { - frappe.model.set_value( - row.doctype, - row.name, - dimension["fieldname"], - default_dimension - ); - }); - } - } - } - }); + // don't set default dimensions if any of the dimension is already set due to mapping + if (frm.doc.__onload?.load_after_mapping) { + for (const dimension of this.accounting_dimensions) { + if (frm.doc[dimension["fieldname"]]) return; + } } + + this.accounting_dimensions.forEach((dimension) => { + const default_dimension = this.default_dimensions[frm.doc.company][dimension["fieldname"]]; + + if (!default_dimension) return; + + if (frappe.meta.has_field(doctype, dimension["fieldname"])) { + frm.set_value(dimension["fieldname"], default_dimension); + } + + (frm.doc.items || frm.doc.accounts || []).forEach((row) => { + frappe.model.set_value(row.doctype, row.name, dimension["fieldname"], default_dimension); + }); + }); }, copy_dimension_from_first_row(frm, cdt, cdn, fieldname) { diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 2477444dab6..58fef47d725 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -167,6 +167,7 @@ class Company(NestedSet): frappe.clear_cache() def create_default_warehouses(self): + parent_warehouse = None for wh_detail in [ {"warehouse_name": _("All Warehouses"), "is_group": 1}, {"warehouse_name": _("Stores"), "is_group": 0}, @@ -174,24 +175,31 @@ class Company(NestedSet): {"warehouse_name": _("Finished Goods"), "is_group": 0}, {"warehouse_name": _("Goods In Transit"), "is_group": 0, "warehouse_type": "Transit"}, ]: - if not frappe.db.exists("Warehouse", "{} - {}".format(wh_detail["warehouse_name"], self.abbr)): - warehouse = frappe.get_doc( - { - "doctype": "Warehouse", - "warehouse_name": wh_detail["warehouse_name"], - "is_group": wh_detail["is_group"], - "company": self.name, - "parent_warehouse": "{} - {}".format(_("All Warehouses"), self.abbr) - if not wh_detail["is_group"] - else "", - "warehouse_type": wh_detail["warehouse_type"] - if "warehouse_type" in wh_detail - else None, - } - ) - warehouse.flags.ignore_permissions = True - warehouse.flags.ignore_mandatory = True - warehouse.insert() + if frappe.db.exists( + "Warehouse", + { + "warehouse_name": wh_detail["warehouse_name"], + "company": self.name, + }, + ): + continue + + warehouse = frappe.get_doc( + { + "doctype": "Warehouse", + "warehouse_name": wh_detail["warehouse_name"], + "is_group": wh_detail["is_group"], + "company": self.name, + "parent_warehouse": parent_warehouse, + "warehouse_type": wh_detail.get("warehouse_type"), + } + ) + warehouse.flags.ignore_permissions = True + warehouse.flags.ignore_mandatory = True + warehouse.insert() + + if wh_detail["is_group"]: + parent_warehouse = warehouse.name def create_default_accounts(self): from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts