Merge pull request #23001 from nabinhait/inclusive-tax-based-on-item-quantity
fix: Calculate taxes if tax is based on item quantity and inclusive on item price
This commit is contained in:
commit
1d5ab618d2
@ -206,10 +206,19 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
"rate": 14,
|
"rate": 14,
|
||||||
'included_in_print_rate': 1
|
'included_in_print_rate': 1
|
||||||
})
|
})
|
||||||
|
si.append("taxes", {
|
||||||
|
"charge_type": "On Item Quantity",
|
||||||
|
"account_head": "_Test Account Education Cess - _TC",
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
|
"description": "CESS",
|
||||||
|
"rate": 5,
|
||||||
|
'included_in_print_rate': 1
|
||||||
|
})
|
||||||
si.insert()
|
si.insert()
|
||||||
|
|
||||||
# with inclusive tax
|
# with inclusive tax
|
||||||
self.assertEqual(si.net_total, 4385.96)
|
self.assertEqual(si.items[0].net_amount, 3947.368421052631)
|
||||||
|
self.assertEqual(si.net_total, 3947.37)
|
||||||
self.assertEqual(si.grand_total, 5000)
|
self.assertEqual(si.grand_total, 5000)
|
||||||
|
|
||||||
si.reload()
|
si.reload()
|
||||||
@ -222,8 +231,8 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
si.save()
|
si.save()
|
||||||
|
|
||||||
# with inclusive tax and additional discount
|
# with inclusive tax and additional discount
|
||||||
self.assertEqual(si.net_total, 4285.96)
|
self.assertEqual(si.net_total, 3847.37)
|
||||||
self.assertEqual(si.grand_total, 4885.99)
|
self.assertEqual(si.grand_total, 4886)
|
||||||
|
|
||||||
si.reload()
|
si.reload()
|
||||||
|
|
||||||
@ -235,7 +244,7 @@ class TestSalesInvoice(unittest.TestCase):
|
|||||||
si.save()
|
si.save()
|
||||||
|
|
||||||
# with inclusive tax and additional discount
|
# with inclusive tax and additional discount
|
||||||
self.assertEqual(si.net_total, 4298.25)
|
self.assertEqual(si.net_total, 3859.65)
|
||||||
self.assertEqual(si.grand_total, 4900.00)
|
self.assertEqual(si.grand_total, 4900.00)
|
||||||
|
|
||||||
def test_sales_invoice_discount_amount(self):
|
def test_sales_invoice_discount_amount(self):
|
||||||
|
@ -985,7 +985,7 @@ def validate_inclusive_tax(tax, doc):
|
|||||||
# all rows about the reffered tax should be inclusive
|
# all rows about the reffered tax should be inclusive
|
||||||
_on_previous_row_error("1 - %d" % (tax.row_id,))
|
_on_previous_row_error("1 - %d" % (tax.row_id,))
|
||||||
elif tax.get("category") == "Valuation":
|
elif tax.get("category") == "Valuation":
|
||||||
frappe.throw(_("Valuation type charges can not marked as Inclusive"))
|
frappe.throw(_("Valuation type charges can not be marked as Inclusive"))
|
||||||
|
|
||||||
|
|
||||||
def set_balance_in_account_currency(gl_dict, account_currency=None, conversion_rate=None, company_currency=None):
|
def set_balance_in_account_currency(gl_dict, account_currency=None, conversion_rate=None, company_currency=None):
|
||||||
|
@ -161,8 +161,9 @@ class calculate_taxes_and_totals(object):
|
|||||||
for item in self.doc.get("items"):
|
for item in self.doc.get("items"):
|
||||||
item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
|
item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
|
||||||
cumulated_tax_fraction = 0
|
cumulated_tax_fraction = 0
|
||||||
|
total_inclusive_tax_amount_per_qty = 0
|
||||||
for i, tax in enumerate(self.doc.get("taxes")):
|
for i, tax in enumerate(self.doc.get("taxes")):
|
||||||
tax.tax_fraction_for_current_item = self.get_current_tax_fraction(tax, item_tax_map)
|
tax.tax_fraction_for_current_item, inclusive_tax_amount_per_qty = self.get_current_tax_fraction(tax, item_tax_map)
|
||||||
|
|
||||||
if i==0:
|
if i==0:
|
||||||
tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item
|
tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item
|
||||||
@ -172,9 +173,12 @@ class calculate_taxes_and_totals(object):
|
|||||||
+ tax.tax_fraction_for_current_item
|
+ tax.tax_fraction_for_current_item
|
||||||
|
|
||||||
cumulated_tax_fraction += tax.tax_fraction_for_current_item
|
cumulated_tax_fraction += tax.tax_fraction_for_current_item
|
||||||
|
total_inclusive_tax_amount_per_qty += inclusive_tax_amount_per_qty * flt(item.stock_qty)
|
||||||
|
|
||||||
if cumulated_tax_fraction and not self.discount_amount_applied and item.qty:
|
if not self.discount_amount_applied and item.qty and (cumulated_tax_fraction or total_inclusive_tax_amount_per_qty):
|
||||||
item.net_amount = flt(item.amount / (1 + cumulated_tax_fraction))
|
amount = flt(item.amount) - total_inclusive_tax_amount_per_qty
|
||||||
|
|
||||||
|
item.net_amount = flt(amount / (1 + cumulated_tax_fraction))
|
||||||
item.net_rate = flt(item.net_amount / item.qty, item.precision("net_rate"))
|
item.net_rate = flt(item.net_amount / item.qty, item.precision("net_rate"))
|
||||||
item.discount_percentage = flt(item.discount_percentage,
|
item.discount_percentage = flt(item.discount_percentage,
|
||||||
item.precision("discount_percentage"))
|
item.precision("discount_percentage"))
|
||||||
@ -190,6 +194,7 @@ class calculate_taxes_and_totals(object):
|
|||||||
from tax inclusive amount
|
from tax inclusive amount
|
||||||
"""
|
"""
|
||||||
current_tax_fraction = 0
|
current_tax_fraction = 0
|
||||||
|
inclusive_tax_amount_per_qty = 0
|
||||||
|
|
||||||
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)
|
||||||
@ -204,10 +209,15 @@ class calculate_taxes_and_totals(object):
|
|||||||
elif tax.charge_type == "On Previous Row Total":
|
elif tax.charge_type == "On Previous Row Total":
|
||||||
current_tax_fraction = (tax_rate / 100.0) * \
|
current_tax_fraction = (tax_rate / 100.0) * \
|
||||||
self.doc.get("taxes")[cint(tax.row_id) - 1].grand_total_fraction_for_current_item
|
self.doc.get("taxes")[cint(tax.row_id) - 1].grand_total_fraction_for_current_item
|
||||||
|
|
||||||
|
elif tax.charge_type == "On Item Quantity":
|
||||||
|
inclusive_tax_amount_per_qty = flt(tax_rate)
|
||||||
|
|
||||||
if getattr(tax, "add_deduct_tax", None):
|
if getattr(tax, "add_deduct_tax", None) and tax.add_deduct_tax == "Deduct":
|
||||||
current_tax_fraction *= -1.0 if (tax.add_deduct_tax == "Deduct") else 1.0
|
current_tax_fraction *= -1.0
|
||||||
return current_tax_fraction
|
inclusive_tax_amount_per_qty *= -1.0
|
||||||
|
|
||||||
|
return current_tax_fraction, inclusive_tax_amount_per_qty
|
||||||
|
|
||||||
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:
|
||||||
@ -321,7 +331,7 @@ class calculate_taxes_and_totals(object):
|
|||||||
current_tax_amount = (tax_rate / 100.0) * \
|
current_tax_amount = (tax_rate / 100.0) * \
|
||||||
self.doc.get("taxes")[cint(tax.row_id) - 1].grand_total_for_current_item
|
self.doc.get("taxes")[cint(tax.row_id) - 1].grand_total_for_current_item
|
||||||
elif tax.charge_type == "On Item Quantity":
|
elif tax.charge_type == "On Item Quantity":
|
||||||
current_tax_amount = tax_rate * item.stock_qty
|
current_tax_amount = tax_rate * item.qty
|
||||||
|
|
||||||
self.set_item_wise_tax(item, tax, tax_rate, current_tax_amount)
|
self.set_item_wise_tax(item, tax, tax_rate, current_tax_amount)
|
||||||
|
|
||||||
@ -472,7 +482,7 @@ class calculate_taxes_and_totals(object):
|
|||||||
actual_taxes_dict = {}
|
actual_taxes_dict = {}
|
||||||
|
|
||||||
for tax in self.doc.get("taxes"):
|
for tax in self.doc.get("taxes"):
|
||||||
if tax.charge_type == "Actual":
|
if tax.charge_type in ["Actual", "On Item Quantity"]:
|
||||||
tax_amount = self.get_tax_amount_if_for_valuation_or_deduction(tax.tax_amount, tax)
|
tax_amount = self.get_tax_amount_if_for_valuation_or_deduction(tax.tax_amount, tax)
|
||||||
actual_taxes_dict.setdefault(tax.idx, tax_amount)
|
actual_taxes_dict.setdefault(tax.idx, tax_amount)
|
||||||
elif tax.row_id in actual_taxes_dict:
|
elif tax.row_id in actual_taxes_dict:
|
||||||
|
@ -163,9 +163,11 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
|||||||
$.each(me.frm.doc["items"] || [], function(n, item) {
|
$.each(me.frm.doc["items"] || [], function(n, item) {
|
||||||
var item_tax_map = me._load_item_tax_rate(item.item_tax_rate);
|
var item_tax_map = me._load_item_tax_rate(item.item_tax_rate);
|
||||||
var cumulated_tax_fraction = 0.0;
|
var cumulated_tax_fraction = 0.0;
|
||||||
|
var total_inclusive_tax_amount_per_qty = 0;
|
||||||
$.each(me.frm.doc["taxes"] || [], function(i, tax) {
|
$.each(me.frm.doc["taxes"] || [], function(i, tax) {
|
||||||
tax.tax_fraction_for_current_item = me.get_current_tax_fraction(tax, item_tax_map);
|
var current_tax_fraction = me.get_current_tax_fraction(tax, item_tax_map);
|
||||||
|
tax.tax_fraction_for_current_item = current_tax_fraction[0];
|
||||||
|
var inclusive_tax_amount_per_qty = current_tax_fraction[1];
|
||||||
|
|
||||||
if(i==0) {
|
if(i==0) {
|
||||||
tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item;
|
tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item;
|
||||||
@ -176,10 +178,12 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
cumulated_tax_fraction += tax.tax_fraction_for_current_item;
|
cumulated_tax_fraction += tax.tax_fraction_for_current_item;
|
||||||
|
total_inclusive_tax_amount_per_qty += inclusive_tax_amount_per_qty * flt(item.qty);
|
||||||
});
|
});
|
||||||
|
|
||||||
if(cumulated_tax_fraction && !me.discount_amount_applied) {
|
if(!me.discount_amount_applied && item.qty && (total_inclusive_tax_amount_per_qty || cumulated_tax_fraction)) {
|
||||||
item.net_amount = flt(item.amount / (1 + cumulated_tax_fraction));
|
var amount = flt(item.amount) - total_inclusive_tax_amount_per_qty;
|
||||||
|
item.net_amount = flt(amount / (1 + cumulated_tax_fraction));
|
||||||
item.net_rate = item.qty ? flt(item.net_amount / item.qty, precision("net_rate", item)) : 0;
|
item.net_rate = item.qty ? flt(item.net_amount / item.qty, precision("net_rate", item)) : 0;
|
||||||
|
|
||||||
me.set_in_company_currency(item, ["net_rate", "net_amount"]);
|
me.set_in_company_currency(item, ["net_rate", "net_amount"]);
|
||||||
@ -191,6 +195,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
|||||||
// Get tax fraction for calculating tax exclusive amount
|
// Get tax fraction for calculating tax exclusive amount
|
||||||
// from tax inclusive amount
|
// from tax inclusive amount
|
||||||
var current_tax_fraction = 0.0;
|
var current_tax_fraction = 0.0;
|
||||||
|
var inclusive_tax_amount_per_qty = 0;
|
||||||
|
|
||||||
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);
|
||||||
@ -205,13 +210,16 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
|||||||
} else if(tax.charge_type == "On Previous Row Total") {
|
} else if(tax.charge_type == "On Previous Row Total") {
|
||||||
current_tax_fraction = (tax_rate / 100.0) *
|
current_tax_fraction = (tax_rate / 100.0) *
|
||||||
this.frm.doc["taxes"][cint(tax.row_id) - 1].grand_total_fraction_for_current_item;
|
this.frm.doc["taxes"][cint(tax.row_id) - 1].grand_total_fraction_for_current_item;
|
||||||
|
} else if (tax.charge_type == "On Item Quantity") {
|
||||||
|
inclusive_tax_amount_per_qty = flt(tax_rate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tax.add_deduct_tax) {
|
if(tax.add_deduct_tax && tax.add_deduct_tax == "Deduct") {
|
||||||
current_tax_fraction *= (tax.add_deduct_tax == "Deduct") ? -1.0 : 1.0;
|
current_tax_fraction *= -1;
|
||||||
|
inclusive_tax_amount_per_qty *= -1;
|
||||||
}
|
}
|
||||||
return current_tax_fraction;
|
return [current_tax_fraction, inclusive_tax_amount_per_qty];
|
||||||
},
|
},
|
||||||
|
|
||||||
_get_tax_rate: function(tax, item_tax_map) {
|
_get_tax_rate: function(tax, item_tax_map) {
|
||||||
@ -360,8 +368,9 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
|||||||
} else if(tax.charge_type == "On Previous Row Total") {
|
} else if(tax.charge_type == "On Previous Row Total") {
|
||||||
current_tax_amount = (tax_rate / 100.0) *
|
current_tax_amount = (tax_rate / 100.0) *
|
||||||
this.frm.doc["taxes"][cint(tax.row_id) - 1].grand_total_for_current_item;
|
this.frm.doc["taxes"][cint(tax.row_id) - 1].grand_total_for_current_item;
|
||||||
|
} else if (tax.charge_type == "On Item Quantity") {
|
||||||
|
current_tax_amount = tax_rate * item.qty;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.set_item_wise_tax(item, tax, tax_rate, current_tax_amount);
|
this.set_item_wise_tax(item, tax, tax_rate, current_tax_amount);
|
||||||
|
|
||||||
return current_tax_amount;
|
return current_tax_amount;
|
||||||
@ -573,7 +582,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
|||||||
var actual_taxes_dict = {};
|
var actual_taxes_dict = {};
|
||||||
|
|
||||||
$.each(this.frm.doc["taxes"] || [], function(i, tax) {
|
$.each(this.frm.doc["taxes"] || [], function(i, tax) {
|
||||||
if (tax.charge_type == "Actual") {
|
if (in_list(["Actual", "On Item Quantity"], tax.charge_type)) {
|
||||||
var tax_amount = (tax.category == "Valuation") ? 0.0 : tax.tax_amount;
|
var tax_amount = (tax.category == "Valuation") ? 0.0 : tax.tax_amount;
|
||||||
tax_amount *= (tax.add_deduct_tax == "Deduct") ? -1.0 : 1.0;
|
tax_amount *= (tax.add_deduct_tax == "Deduct") ? -1.0 : 1.0;
|
||||||
actual_taxes_dict[tax.idx] = tax_amount;
|
actual_taxes_dict[tax.idx] = tax_amount;
|
||||||
@ -586,7 +595,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
|
|||||||
$.each(actual_taxes_dict, function(key, value) {
|
$.each(actual_taxes_dict, function(key, value) {
|
||||||
if (value) total_actual_tax += value;
|
if (value) total_actual_tax += value;
|
||||||
});
|
});
|
||||||
|
|
||||||
return flt(this.frm.doc.grand_total - total_actual_tax, precision("grand_total"));
|
return flt(this.frm.doc.grand_total - total_actual_tax, precision("grand_total"));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user