mirror of
https://github.com/frappe/erpnext.git
synced 2026-04-27 10:38:30 +00:00
feat: add support for 'not applicable' tax in item tax templates (#50898)
* feat: add support for 'not applicable' tax in item tax templates
* refactor: remove unused imports
* fix: import NOT_APPLICABLE_TAX in get_item_tax_map function
* fix: add item wise tax details for not applicable taxes
* test: added test case for `not_applicable`
* fix: do not create item wise tax details for not applicable tax
* fix: ensure tax rate is set to 0 for not applicable tax rows
* refactor: changes as per review
* test: update selling settings
* test: correct settings
* fix: return both net and current tax amounts for not applicable tax
(cherry picked from commit 453fe376ab)
This commit is contained in:
@@ -47,3 +47,12 @@ frappe.ui.form.on("Item Tax Template", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frappe.ui.form.on("Item Tax Template Detail", {
|
||||||
|
not_applicable: function (frm, cdt, cdn) {
|
||||||
|
let row = locals[cdt][cdn];
|
||||||
|
if (row.not_applicable) {
|
||||||
|
frappe.model.set_value(cdt, cdn, "tax_rate", 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|||||||
@@ -27,8 +27,15 @@ class ItemTaxTemplate(Document):
|
|||||||
# end: auto-generated types
|
# end: auto-generated types
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
self.set_zero_rate_for_not_applicable_tax()
|
||||||
self.validate_tax_accounts()
|
self.validate_tax_accounts()
|
||||||
|
|
||||||
|
def set_zero_rate_for_not_applicable_tax(self):
|
||||||
|
"""Ensure tax_rate is 0 for any row marked as not applicable."""
|
||||||
|
for row in self.get("taxes"):
|
||||||
|
if row.not_applicable:
|
||||||
|
row.tax_rate = 0
|
||||||
|
|
||||||
def autoname(self):
|
def autoname(self):
|
||||||
if self.company and self.title:
|
if self.company and self.title:
|
||||||
abbr = frappe.get_cached_value("Company", self.company, "abbr")
|
abbr = frappe.get_cached_value("Company", self.company, "abbr")
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"tax_type",
|
"tax_type",
|
||||||
"tax_rate"
|
"tax_rate",
|
||||||
|
"not_applicable"
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@@ -21,18 +22,28 @@
|
|||||||
"fieldname": "tax_rate",
|
"fieldname": "tax_rate",
|
||||||
"fieldtype": "Float",
|
"fieldtype": "Float",
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"label": "Tax Rate"
|
"label": "Tax Rate",
|
||||||
|
"read_only_depends_on": "eval:doc.not_applicable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"description": "Check if this tax is not applicable to items (distinct from 0% rate)",
|
||||||
|
"fieldname": "not_applicable",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Not Applicable"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"links": [],
|
"links": [],
|
||||||
"modified": "2024-03-27 13:09:55.735360",
|
"modified": "2025-12-26 17:19:18.791891",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Item Tax Template Detail",
|
"name": "Item Tax Template Detail",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
|
"row_format": "Dynamic",
|
||||||
"sort_field": "creation",
|
"sort_field": "creation",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"states": [],
|
"states": [],
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class ItemTaxTemplateDetail(Document):
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from frappe.types import DF
|
from frappe.types import DF
|
||||||
|
|
||||||
|
not_applicable: DF.Check
|
||||||
parent: DF.Data
|
parent: DF.Data
|
||||||
parentfield: DF.Data
|
parentfield: DF.Data
|
||||||
parenttype: DF.Data
|
parenttype: DF.Data
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ from erpnext.setup.utils import get_exchange_rate
|
|||||||
from erpnext.stock.doctype.item.item import get_uom_conv_factor
|
from erpnext.stock.doctype.item.item import get_uom_conv_factor
|
||||||
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
|
from erpnext.stock.doctype.packed_item.packed_item import make_packing_list
|
||||||
from erpnext.stock.get_item_details import (
|
from erpnext.stock.get_item_details import (
|
||||||
|
NOT_APPLICABLE_TAX,
|
||||||
ItemDetailsCtx,
|
ItemDetailsCtx,
|
||||||
_get_item_tax_template,
|
_get_item_tax_template,
|
||||||
get_conversion_factor,
|
get_conversion_factor,
|
||||||
@@ -3684,8 +3685,11 @@ def add_taxes_from_tax_template(child_item, parent_doc, db_insert=True):
|
|||||||
|
|
||||||
if child_item.get("item_tax_rate") and add_taxes_from_item_tax_template:
|
if child_item.get("item_tax_rate") and add_taxes_from_item_tax_template:
|
||||||
tax_map = json.loads(child_item.get("item_tax_rate"))
|
tax_map = json.loads(child_item.get("item_tax_rate"))
|
||||||
for tax_type in tax_map:
|
for tax_type, tax_rate in tax_map.items():
|
||||||
tax_rate = flt(tax_map[tax_type])
|
if tax_rate == NOT_APPLICABLE_TAX:
|
||||||
|
continue
|
||||||
|
|
||||||
|
tax_rate = flt(tax_rate)
|
||||||
taxes = parent_doc.get("taxes") or []
|
taxes = parent_doc.get("taxes") or []
|
||||||
# add new row for tax head only if missing
|
# add new row for tax head only if missing
|
||||||
found = any(tax.account_head == tax_type for tax in taxes)
|
found = any(tax.account_head == tax_type for tax in taxes)
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ from erpnext.buying.utils import update_last_purchase_rate, validate_for_items
|
|||||||
from erpnext.controllers.accounts_controller import get_taxes_and_charges
|
from erpnext.controllers.accounts_controller import get_taxes_and_charges
|
||||||
from erpnext.controllers.sales_and_purchase_return import get_rate_for_return
|
from erpnext.controllers.sales_and_purchase_return import get_rate_for_return
|
||||||
from erpnext.controllers.subcontracting_controller import SubcontractingController
|
from erpnext.controllers.subcontracting_controller import SubcontractingController
|
||||||
from erpnext.stock.get_item_details import get_conversion_factor, get_item_defaults
|
from erpnext.stock.get_item_details import (
|
||||||
|
NOT_APPLICABLE_TAX,
|
||||||
|
get_conversion_factor,
|
||||||
|
get_item_defaults,
|
||||||
|
)
|
||||||
from erpnext.stock.utils import get_incoming_rate
|
from erpnext.stock.utils import get_incoming_rate
|
||||||
|
|
||||||
|
|
||||||
@@ -523,6 +527,9 @@ class BuyingController(SubcontractingController):
|
|||||||
if account not in tax_accounts:
|
if account not in tax_accounts:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if rate == NOT_APPLICABLE_TAX:
|
||||||
|
continue
|
||||||
|
|
||||||
net_rate = item.base_net_amount
|
net_rate = item.base_net_amount
|
||||||
if item.sales_incoming_rate:
|
if item.sales_incoming_rate:
|
||||||
net_rate = item.qty * item.sales_incoming_rate
|
net_rate = item.qty * item.sales_incoming_rate
|
||||||
|
|||||||
@@ -20,7 +20,12 @@ from erpnext.controllers.accounts_controller import (
|
|||||||
validate_taxes_and_charges,
|
validate_taxes_and_charges,
|
||||||
)
|
)
|
||||||
from erpnext.deprecation_dumpster import deprecated
|
from erpnext.deprecation_dumpster import deprecated
|
||||||
from erpnext.stock.get_item_details import ItemDetailsCtx, _get_item_tax_template, get_item_tax_map
|
from erpnext.stock.get_item_details import (
|
||||||
|
NOT_APPLICABLE_TAX,
|
||||||
|
ItemDetailsCtx,
|
||||||
|
_get_item_tax_template,
|
||||||
|
get_item_tax_map,
|
||||||
|
)
|
||||||
from erpnext.utilities.regional import temporary_flag
|
from erpnext.utilities.regional import temporary_flag
|
||||||
|
|
||||||
|
|
||||||
@@ -358,6 +363,9 @@ class calculate_taxes_and_totals:
|
|||||||
if cint(tax.included_in_print_rate):
|
if cint(tax.included_in_print_rate):
|
||||||
tax_rate = self._get_tax_rate(tax, item_tax_map)
|
tax_rate = self._get_tax_rate(tax, item_tax_map)
|
||||||
|
|
||||||
|
if tax_rate == NOT_APPLICABLE_TAX:
|
||||||
|
return current_tax_fraction, inclusive_tax_amount_per_qty
|
||||||
|
|
||||||
if tax.charge_type == "On Net Total":
|
if tax.charge_type == "On Net Total":
|
||||||
current_tax_fraction = tax_rate / 100.0
|
current_tax_fraction = tax_rate / 100.0
|
||||||
|
|
||||||
@@ -382,9 +390,12 @@ class calculate_taxes_and_totals:
|
|||||||
|
|
||||||
def _get_tax_rate(self, tax, item_tax_map):
|
def _get_tax_rate(self, tax, item_tax_map):
|
||||||
if tax.account_head in item_tax_map:
|
if tax.account_head in item_tax_map:
|
||||||
return flt(item_tax_map.get(tax.account_head), self.doc.precision("rate", tax))
|
rate = item_tax_map[tax.account_head]
|
||||||
else:
|
if rate == NOT_APPLICABLE_TAX:
|
||||||
return tax.rate
|
return NOT_APPLICABLE_TAX
|
||||||
|
return flt(rate, self.doc.precision("rate", tax))
|
||||||
|
|
||||||
|
return tax.rate
|
||||||
|
|
||||||
def calculate_net_total(self):
|
def calculate_net_total(self):
|
||||||
self.doc.total_qty = (
|
self.doc.total_qty = (
|
||||||
@@ -594,6 +605,9 @@ class calculate_taxes_and_totals:
|
|||||||
current_tax_amount = 0.0
|
current_tax_amount = 0.0
|
||||||
current_net_amount = 0.0
|
current_net_amount = 0.0
|
||||||
|
|
||||||
|
if tax_rate == NOT_APPLICABLE_TAX:
|
||||||
|
return current_net_amount, current_tax_amount
|
||||||
|
|
||||||
if tax.charge_type == "Actual":
|
if tax.charge_type == "Actual":
|
||||||
current_net_amount = item.net_amount
|
current_net_amount = item.net_amount
|
||||||
# distribute the tax amount proportionally to each item row
|
# distribute the tax amount proportionally to each item row
|
||||||
|
|||||||
@@ -301,3 +301,238 @@ class TestTaxesAndTotals(ERPNextTestSuite):
|
|||||||
tax = doc.taxes[0]
|
tax = doc.taxes[0]
|
||||||
detail = doc.item_wise_tax_details[0]
|
detail = doc.item_wise_tax_details[0]
|
||||||
self.assertEqual(detail.amount, tax.base_tax_amount_after_discount_amount)
|
self.assertEqual(detail.amount, tax.base_tax_amount_after_discount_amount)
|
||||||
|
|
||||||
|
@change_settings("Selling Settings", {"allow_multiple_items": 1})
|
||||||
|
def test_not_applicable_tax_in_item_tax_template(self):
|
||||||
|
"""Test that items with 'not applicable' tax don't contribute to net amount of that tax."""
|
||||||
|
template_7pct = frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Item Tax Template",
|
||||||
|
"title": "_Test VAT 7% Template",
|
||||||
|
"company": "_Test Company",
|
||||||
|
"taxes": [
|
||||||
|
{
|
||||||
|
"tax_type": "_Test Account VAT - _TC",
|
||||||
|
"tax_rate": 7,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tax_type": "_Test Account Service Tax - _TC",
|
||||||
|
"tax_rate": 0,
|
||||||
|
"not_applicable": 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
).insert(ignore_if_duplicate=True)
|
||||||
|
|
||||||
|
template_19pct = frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Item Tax Template",
|
||||||
|
"title": "_Test VAT 19% Template",
|
||||||
|
"company": "_Test Company",
|
||||||
|
"taxes": [
|
||||||
|
{
|
||||||
|
"tax_type": "_Test Account VAT - _TC",
|
||||||
|
"tax_rate": 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tax_type": "_Test Account Service Tax - _TC",
|
||||||
|
"tax_rate": 19,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
).insert(ignore_if_duplicate=True)
|
||||||
|
|
||||||
|
self.doc.items[0].item_tax_template = template_7pct.name
|
||||||
|
|
||||||
|
self.doc.append(
|
||||||
|
"items",
|
||||||
|
{
|
||||||
|
"item_code": "_Test Item",
|
||||||
|
"qty": 1,
|
||||||
|
"rate": 100,
|
||||||
|
"income_account": "Sales - _TC",
|
||||||
|
"expense_account": "Cost of Goods Sold - _TC",
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
|
"item_tax_template": template_19pct.name,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.doc.append(
|
||||||
|
"taxes",
|
||||||
|
{
|
||||||
|
"charge_type": "On Net Total",
|
||||||
|
"account_head": "_Test Account VAT - _TC",
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
|
"description": "VAT 7%",
|
||||||
|
"rate": 7,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.doc.append(
|
||||||
|
"taxes",
|
||||||
|
{
|
||||||
|
"charge_type": "On Net Total",
|
||||||
|
"account_head": "_Test Account Service Tax - _TC",
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
|
"description": "VAT 19%",
|
||||||
|
"rate": 19,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.doc.save()
|
||||||
|
|
||||||
|
# VAT 7%: Both items contribute (Item 2 has 0% rate, not "not applicable")
|
||||||
|
self.assertEqual(self.doc.taxes[0].net_amount, 200.0)
|
||||||
|
# Service Tax 19%: Only Item 2 contributes (Item 1 has not_applicable)
|
||||||
|
self.assertEqual(self.doc.taxes[1].net_amount, 100.0)
|
||||||
|
|
||||||
|
expected_values = [
|
||||||
|
{
|
||||||
|
"item_row": self.doc.items[0].name,
|
||||||
|
"tax_row": self.doc.taxes[0].name,
|
||||||
|
"rate": 7.0,
|
||||||
|
"amount": 7.0,
|
||||||
|
"taxable_amount": 100.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item_row": self.doc.items[1].name,
|
||||||
|
"tax_row": self.doc.taxes[0].name,
|
||||||
|
"rate": 0.0,
|
||||||
|
"amount": 0.0,
|
||||||
|
"taxable_amount": 100.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item_row": self.doc.items[1].name,
|
||||||
|
"tax_row": self.doc.taxes[1].name,
|
||||||
|
"rate": 19.0,
|
||||||
|
"amount": 19.0,
|
||||||
|
"taxable_amount": 100.0,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
actual_values = [
|
||||||
|
{
|
||||||
|
"item_row": row.item_row,
|
||||||
|
"tax_row": row.tax_row,
|
||||||
|
"rate": row.rate,
|
||||||
|
"amount": row.amount,
|
||||||
|
"taxable_amount": row.taxable_amount,
|
||||||
|
}
|
||||||
|
for row in self.doc.item_wise_tax_details
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertEqual(actual_values, expected_values)
|
||||||
|
|
||||||
|
def test_not_applicable_tax_in_item_tax_template_with_different_items(self):
|
||||||
|
"""Test that items with 'not applicable' tax don't contribute to net amount of that tax."""
|
||||||
|
template_7pct = frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Item Tax Template",
|
||||||
|
"title": "_Test VAT 7% Template",
|
||||||
|
"company": "_Test Company",
|
||||||
|
"taxes": [
|
||||||
|
{
|
||||||
|
"tax_type": "_Test Account VAT - _TC",
|
||||||
|
"tax_rate": 7,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tax_type": "_Test Account Service Tax - _TC",
|
||||||
|
"tax_rate": 0,
|
||||||
|
"not_applicable": 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
).insert(ignore_if_duplicate=True)
|
||||||
|
|
||||||
|
template_19pct = frappe.get_doc(
|
||||||
|
{
|
||||||
|
"doctype": "Item Tax Template",
|
||||||
|
"title": "_Test VAT 19% Template",
|
||||||
|
"company": "_Test Company",
|
||||||
|
"taxes": [
|
||||||
|
{
|
||||||
|
"tax_type": "_Test Account VAT - _TC",
|
||||||
|
"tax_rate": 0,
|
||||||
|
"not_applicable": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tax_type": "_Test Account Service Tax - _TC",
|
||||||
|
"tax_rate": 19,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
).insert(ignore_if_duplicate=True)
|
||||||
|
|
||||||
|
self.doc.items[0].item_tax_template = template_7pct.name
|
||||||
|
|
||||||
|
self.doc.append(
|
||||||
|
"items",
|
||||||
|
{
|
||||||
|
"item_code": "_Test Item 2",
|
||||||
|
"qty": 1,
|
||||||
|
"rate": 100,
|
||||||
|
"income_account": "Sales - _TC",
|
||||||
|
"expense_account": "Cost of Goods Sold - _TC",
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
|
"item_tax_template": template_19pct.name,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.doc.append(
|
||||||
|
"taxes",
|
||||||
|
{
|
||||||
|
"charge_type": "On Net Total",
|
||||||
|
"account_head": "_Test Account VAT - _TC",
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
|
"description": "VAT 7%",
|
||||||
|
"rate": 0,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.doc.append(
|
||||||
|
"taxes",
|
||||||
|
{
|
||||||
|
"charge_type": "On Net Total",
|
||||||
|
"account_head": "_Test Account Service Tax - _TC",
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
|
"description": "VAT 19%",
|
||||||
|
"rate": 0,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
self.doc.save()
|
||||||
|
|
||||||
|
# VAT 7%: Only Item 1 contributes (Item 2 has not_applicable)
|
||||||
|
self.assertEqual(self.doc.taxes[0].net_amount, 100.0)
|
||||||
|
# Service Tax 19%: Only Item 2 contributes (Item 1 has not_applicable)
|
||||||
|
self.assertEqual(self.doc.taxes[1].net_amount, 100.0)
|
||||||
|
|
||||||
|
expected_values = [
|
||||||
|
{
|
||||||
|
"item_row": self.doc.items[0].name,
|
||||||
|
"tax_row": self.doc.taxes[0].name,
|
||||||
|
"rate": 7.0,
|
||||||
|
"amount": 7.0,
|
||||||
|
"taxable_amount": 100.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"item_row": self.doc.items[1].name,
|
||||||
|
"tax_row": self.doc.taxes[1].name,
|
||||||
|
"rate": 19.0,
|
||||||
|
"amount": 19.0,
|
||||||
|
"taxable_amount": 100.0,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
actual_values = [
|
||||||
|
{
|
||||||
|
"item_row": row.item_row,
|
||||||
|
"tax_row": row.tax_row,
|
||||||
|
"rate": row.rate,
|
||||||
|
"amount": row.amount,
|
||||||
|
"taxable_amount": row.taxable_amount,
|
||||||
|
}
|
||||||
|
for row in self.doc.item_wise_tax_details
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertEqual(actual_values, expected_values)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
// License: GNU General Public License v3. See license.txt
|
// License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
const NOT_APPLICABLE_TAX = "N/A";
|
||||||
|
|
||||||
erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
||||||
setup() {
|
setup() {
|
||||||
this.fetch_round_off_accounts();
|
this.fetch_round_off_accounts();
|
||||||
@@ -299,6 +301,10 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
if (cint(tax.included_in_print_rate)) {
|
if (cint(tax.included_in_print_rate)) {
|
||||||
var tax_rate = this._get_tax_rate(tax, item_tax_map);
|
var tax_rate = this._get_tax_rate(tax, item_tax_map);
|
||||||
|
|
||||||
|
if (tax_rate === NOT_APPLICABLE_TAX) {
|
||||||
|
return [current_tax_fraction, inclusive_tax_amount_per_qty];
|
||||||
|
}
|
||||||
|
|
||||||
if (tax.charge_type == "On Net Total") {
|
if (tax.charge_type == "On Net Total") {
|
||||||
current_tax_fraction = tax_rate / 100.0;
|
current_tax_fraction = tax_rate / 100.0;
|
||||||
} else if (tax.charge_type == "On Previous Row Amount") {
|
} else if (tax.charge_type == "On Previous Row Amount") {
|
||||||
@@ -322,9 +328,14 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_get_tax_rate(tax, item_tax_map) {
|
_get_tax_rate(tax, item_tax_map) {
|
||||||
return Object.keys(item_tax_map).indexOf(tax.account_head) != -1
|
if (tax.account_head in item_tax_map) {
|
||||||
? flt(item_tax_map[tax.account_head], precision("rate", tax))
|
let rate = item_tax_map[tax.account_head];
|
||||||
: tax.rate;
|
if (rate === NOT_APPLICABLE_TAX) {
|
||||||
|
return NOT_APPLICABLE_TAX;
|
||||||
|
}
|
||||||
|
return flt(rate, precision("rate", tax));
|
||||||
|
}
|
||||||
|
return tax.rate;
|
||||||
}
|
}
|
||||||
|
|
||||||
calculate_net_total() {
|
calculate_net_total() {
|
||||||
@@ -368,6 +379,10 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$.each(item_tax_map, function (tax, rate) {
|
$.each(item_tax_map, function (tax, rate) {
|
||||||
|
if (rate === NOT_APPLICABLE_TAX) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let found = (me.frm.doc.taxes || []).find((d) => d.account_head === tax);
|
let found = (me.frm.doc.taxes || []).find((d) => d.account_head === tax);
|
||||||
if (!found) {
|
if (!found) {
|
||||||
let child = frappe.model.add_child(me.frm.doc, "taxes");
|
let child = frappe.model.add_child(me.frm.doc, "taxes");
|
||||||
@@ -524,6 +539,10 @@ erpnext.taxes_and_totals = class TaxesAndTotals extends erpnext.payments {
|
|||||||
var current_tax_amount = 0.0;
|
var current_tax_amount = 0.0;
|
||||||
var current_net_amount = 0.0;
|
var current_net_amount = 0.0;
|
||||||
|
|
||||||
|
if (tax_rate === NOT_APPLICABLE_TAX) {
|
||||||
|
return [current_net_amount, current_tax_amount];
|
||||||
|
}
|
||||||
|
|
||||||
// To set row_id by default as previous row.
|
// To set row_id by default as previous row.
|
||||||
if (["On Previous Row Amount", "On Previous Row Total"].includes(tax.charge_type)) {
|
if (["On Previous Row Amount", "On Previous Row Total"].includes(tax.charge_type)) {
|
||||||
if (tax.idx === 1) {
|
if (tax.idx === 1) {
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ purchase_doctypes = [
|
|||||||
"Purchase Invoice",
|
"Purchase Invoice",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
NOT_APPLICABLE_TAX = "N/A"
|
||||||
|
|
||||||
|
|
||||||
def _preprocess_ctx(ctx):
|
def _preprocess_ctx(ctx):
|
||||||
if not ctx.price_list:
|
if not ctx.price_list:
|
||||||
@@ -836,7 +838,10 @@ def get_item_tax_map(*, doc: str | dict | Document, tax_template: str | None = N
|
|||||||
template = frappe.get_cached_doc("Item Tax Template", tax_template)
|
template = frappe.get_cached_doc("Item Tax Template", tax_template)
|
||||||
for d in template.taxes:
|
for d in template.taxes:
|
||||||
if frappe.get_cached_value("Account", d.tax_type, "company") == doc.get("company"):
|
if frappe.get_cached_value("Account", d.tax_type, "company") == doc.get("company"):
|
||||||
item_tax_map[d.tax_type] = d.tax_rate
|
if d.get("not_applicable"):
|
||||||
|
item_tax_map[d.tax_type] = NOT_APPLICABLE_TAX
|
||||||
|
else:
|
||||||
|
item_tax_map[d.tax_type] = d.tax_rate
|
||||||
|
|
||||||
return json.dumps(item_tax_map) if as_json else item_tax_map
|
return json.dumps(item_tax_map) if as_json else item_tax_map
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from frappe.utils import cint, flt, get_time, now_datetime
|
|||||||
|
|
||||||
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_dimensions
|
from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_dimensions
|
||||||
from erpnext.controllers.status_updater import StatusUpdater
|
from erpnext.controllers.status_updater import StatusUpdater
|
||||||
from erpnext.stock.get_item_details import get_item_details
|
from erpnext.stock.get_item_details import NOT_APPLICABLE_TAX, get_item_details
|
||||||
from erpnext.stock.utils import get_incoming_rate
|
from erpnext.stock.utils import get_incoming_rate
|
||||||
|
|
||||||
|
|
||||||
@@ -367,6 +367,9 @@ class TransactionBase(StatusUpdater):
|
|||||||
):
|
):
|
||||||
item_tax_template = frappe.json.loads(item_details.item_tax_rate)
|
item_tax_template = frappe.json.loads(item_details.item_tax_rate)
|
||||||
for tax_head, _rate in item_tax_template.items():
|
for tax_head, _rate in item_tax_template.items():
|
||||||
|
if _rate == NOT_APPLICABLE_TAX:
|
||||||
|
continue
|
||||||
|
|
||||||
found = [x for x in self.taxes if x.account_head == tax_head]
|
found = [x for x in self.taxes if x.account_head == tax_head]
|
||||||
if not found:
|
if not found:
|
||||||
self.append("taxes", {"charge_type": "On Net Total", "account_head": tax_head, "rate": 0})
|
self.append("taxes", {"charge_type": "On Net Total", "account_head": tax_head, "rate": 0})
|
||||||
|
|||||||
Reference in New Issue
Block a user