mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-07 07:02:54 +00:00
Merge pull request #47205 from frappe/version-14-hotfix
chore: release v14
This commit is contained in:
7
.github/workflows/linters.yml
vendored
7
.github/workflows/linters.yml
vendored
@@ -9,15 +9,16 @@ jobs:
|
|||||||
name: linters
|
name: linters
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Set up Python 3.10
|
- name: Set up Python 3.10
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.10'
|
||||||
|
cache: pip
|
||||||
|
|
||||||
- name: Install and Run Pre-commit
|
- name: Install and Run Pre-commit
|
||||||
uses: pre-commit/action@v2.0.3
|
uses: pre-commit/action@v3.0.0
|
||||||
|
|
||||||
- name: Download Semgrep rules
|
- name: Download Semgrep rules
|
||||||
run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules
|
run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
exclude: 'node_modules|.git'
|
exclude: 'node_modules|.git'
|
||||||
default_stages: [commit]
|
default_stages: [pre-commit]
|
||||||
fail_fast: false
|
fail_fast: false
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
from frappe.utils import getdate
|
||||||
|
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
@@ -33,6 +34,7 @@ def execute(filters=None):
|
|||||||
|
|
||||||
def validate_filters(filters):
|
def validate_filters(filters):
|
||||||
"""Validate if dates are properly set"""
|
"""Validate if dates are properly set"""
|
||||||
|
filters = frappe._dict(filters or {})
|
||||||
if filters.from_date > filters.to_date:
|
if filters.from_date > filters.to_date:
|
||||||
frappe.throw(_("From Date must be before 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:
|
if not tax_withholding_category:
|
||||||
tax_withholding_category = party_map.get(party, {}).get("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 net_total_map.get((voucher_type, name)):
|
||||||
if voucher_type == "Journal Entry" and tax_amount and rate:
|
if voucher_type == "Journal Entry" and tax_amount and rate:
|
||||||
# back calcalute total amount from rate and tax_amount
|
# 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):
|
def get_tax_rate_map(filters):
|
||||||
rate_map = frappe.get_all(
|
rate_map = frappe.get_all(
|
||||||
"Tax Withholding Rate",
|
"Tax Withholding Rate",
|
||||||
filters={
|
filters={"from_date": ("<=", filters.to_date), "to_date": (">=", filters.from_date)},
|
||||||
"from_date": ("<=", filters.get("from_date")),
|
fields=["parent", "tax_withholding_rate", "from_date", "to_date"],
|
||||||
"to_date": (">=", filters.get("to_date")),
|
|
||||||
},
|
|
||||||
fields=["parent", "tax_withholding_rate"],
|
|
||||||
as_list=1,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.tests.utils import FrappeTestCase
|
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.payment_entry.test_payment_entry import create_payment_entry
|
||||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
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)
|
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):
|
def check_expected_values(self, result, expected_values):
|
||||||
for i in range(len(result)):
|
for i in range(len(result)):
|
||||||
voucher = frappe._dict(result[i])
|
voucher = frappe._dict(result[i])
|
||||||
|
|||||||
@@ -77,35 +77,34 @@ erpnext.accounts.dimensions = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
update_dimension(frm, doctype) {
|
update_dimension(frm, doctype) {
|
||||||
if (this.accounting_dimensions) {
|
if (
|
||||||
this.accounting_dimensions.forEach((dimension) => {
|
!this.accounting_dimensions ||
|
||||||
if (frm.is_new()) {
|
!frm.is_new() ||
|
||||||
if (
|
!frm.doc.company ||
|
||||||
frm.doc.company &&
|
!this.default_dimensions?.[frm.doc.company]
|
||||||
Object.keys(this.default_dimensions || {}).length > 0 &&
|
)
|
||||||
this.default_dimensions[frm.doc.company]
|
return;
|
||||||
) {
|
|
||||||
let default_dimension =
|
|
||||||
this.default_dimensions[frm.doc.company][dimension["fieldname"]];
|
|
||||||
|
|
||||||
if (default_dimension) {
|
// don't set default dimensions if any of the dimension is already set due to mapping
|
||||||
if (frappe.meta.has_field(doctype, dimension["fieldname"])) {
|
if (frm.doc.__onload?.load_after_mapping) {
|
||||||
frm.set_value(dimension["fieldname"], default_dimension);
|
for (const dimension of this.accounting_dimensions) {
|
||||||
}
|
if (frm.doc[dimension["fieldname"]]) return;
|
||||||
|
}
|
||||||
$.each(frm.doc.items || frm.doc.accounts || [], function (i, row) {
|
|
||||||
frappe.model.set_value(
|
|
||||||
row.doctype,
|
|
||||||
row.name,
|
|
||||||
dimension["fieldname"],
|
|
||||||
default_dimension
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
copy_dimension_from_first_row(frm, cdt, cdn, fieldname) {
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ class Company(NestedSet):
|
|||||||
frappe.clear_cache()
|
frappe.clear_cache()
|
||||||
|
|
||||||
def create_default_warehouses(self):
|
def create_default_warehouses(self):
|
||||||
|
parent_warehouse = None
|
||||||
for wh_detail in [
|
for wh_detail in [
|
||||||
{"warehouse_name": _("All Warehouses"), "is_group": 1},
|
{"warehouse_name": _("All Warehouses"), "is_group": 1},
|
||||||
{"warehouse_name": _("Stores"), "is_group": 0},
|
{"warehouse_name": _("Stores"), "is_group": 0},
|
||||||
@@ -174,24 +175,31 @@ class Company(NestedSet):
|
|||||||
{"warehouse_name": _("Finished Goods"), "is_group": 0},
|
{"warehouse_name": _("Finished Goods"), "is_group": 0},
|
||||||
{"warehouse_name": _("Goods In Transit"), "is_group": 0, "warehouse_type": "Transit"},
|
{"warehouse_name": _("Goods In Transit"), "is_group": 0, "warehouse_type": "Transit"},
|
||||||
]:
|
]:
|
||||||
if not frappe.db.exists("Warehouse", "{} - {}".format(wh_detail["warehouse_name"], self.abbr)):
|
if frappe.db.exists(
|
||||||
warehouse = frappe.get_doc(
|
"Warehouse",
|
||||||
{
|
{
|
||||||
"doctype": "Warehouse",
|
"warehouse_name": wh_detail["warehouse_name"],
|
||||||
"warehouse_name": wh_detail["warehouse_name"],
|
"company": self.name,
|
||||||
"is_group": wh_detail["is_group"],
|
},
|
||||||
"company": self.name,
|
):
|
||||||
"parent_warehouse": "{} - {}".format(_("All Warehouses"), self.abbr)
|
continue
|
||||||
if not wh_detail["is_group"]
|
|
||||||
else "",
|
warehouse = frappe.get_doc(
|
||||||
"warehouse_type": wh_detail["warehouse_type"]
|
{
|
||||||
if "warehouse_type" in wh_detail
|
"doctype": "Warehouse",
|
||||||
else None,
|
"warehouse_name": wh_detail["warehouse_name"],
|
||||||
}
|
"is_group": wh_detail["is_group"],
|
||||||
)
|
"company": self.name,
|
||||||
warehouse.flags.ignore_permissions = True
|
"parent_warehouse": parent_warehouse,
|
||||||
warehouse.flags.ignore_mandatory = True
|
"warehouse_type": wh_detail.get("warehouse_type"),
|
||||||
warehouse.insert()
|
}
|
||||||
|
)
|
||||||
|
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):
|
def create_default_accounts(self):
|
||||||
from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts
|
from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts
|
||||||
|
|||||||
Reference in New Issue
Block a user