From 8a7e283926d51626d9114eaa4f6647b920ad8c9f Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 4 Jun 2021 22:53:26 +0530 Subject: [PATCH 1/4] feat: Item Taxes based on net rate --- erpnext/controllers/taxes_and_totals.py | 4 +- .../public/js/controllers/taxes_and_totals.js | 90 ++++++++++++++++--- erpnext/public/js/controllers/transaction.js | 66 +------------- erpnext/stock/doctype/item/item.py | 6 ++ erpnext/stock/doctype/item_tax/item_tax.json | 20 ++++- erpnext/stock/get_item_details.py | 34 +++++-- 6 files changed, 137 insertions(+), 83 deletions(-) diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 9fae49482dd..80404356346 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -54,6 +54,7 @@ class calculate_taxes_and_totals(object): if item.item_code and item.get('item_tax_template'): item_doc = frappe.get_cached_doc("Item", item.item_code) args = { + 'net_rate': item.net_rate or item.rate, 'tax_category': self.doc.get('tax_category'), 'posting_date': self.doc.get('posting_date'), 'bill_date': self.doc.get('bill_date'), @@ -78,7 +79,8 @@ class calculate_taxes_and_totals(object): taxes = _get_item_tax_template(args, item_taxes + item_group_taxes, for_validate=True) if item.item_tax_template not in taxes: - frappe.throw(_("Row {0}: Invalid Item Tax Template for item {1}").format( + item.item_tax_template = taxes[0] + frappe.msgprint(_("Row {0}: Item Tax template updated as per validity and rate applied").format( item.idx, frappe.bold(item.item_code) )) diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index 2e133bed2eb..ff4898eeff6 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -12,7 +12,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ if (in_list(["Sales Order", "Quotation"], item.parenttype) && item.blanket_order_rate) { effective_item_rate = item.blanket_order_rate; } - if(item.margin_type == "Percentage"){ + if(item.margin_type == "Percentage") { item.rate_with_margin = flt(effective_item_rate) + flt(effective_item_rate) * ( flt(item.margin_rate_or_amount) / 100); } else { @@ -73,15 +73,18 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ }, _calculate_taxes_and_totals: function() { - this.validate_conversion_rate(); - this.calculate_item_values(); - this.initialize_taxes(); - this.determine_exclusive_rate(); - this.calculate_net_total(); - this.calculate_taxes(); - this.manipulate_grand_total_for_inclusive_tax(); - this.calculate_totals(); - this._cleanup(); + frappe.run_serially([ + () => this.validate_conversion_rate(), + () => this.calculate_item_values(), + () => this.update_item_tax_map(), + () => this.initialize_taxes(), + () => this.determine_exclusive_rate(), + () => this.calculate_net_total(), + () => this.calculate_taxes(), + () => this.manipulate_grand_total_for_inclusive_tax(), + () => this.calculate_totals(), + () => this._cleanup() + ]); }, validate_conversion_rate: function() { @@ -263,6 +266,68 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ frappe.model.round_floats_in(this.frm.doc, ["total", "base_total", "net_total", "base_net_total"]); }, + update_item_tax_map: function() { + let me = this; + let item_codes = []; + let item_rates = {}; + $.each(this.frm.doc.items || [], function(i, item) { + if(item.item_code) { + // Use combination of name and item code in case same item is added multiple times + item_codes.push([item.item_code, item.name]); + item_rates[item.name] = item.net_rate; + } + }); + + if(item_codes.length) { + return this.frm.call({ + method: "erpnext.stock.get_item_details.get_item_tax_info", + args: { + company: me.frm.doc.company, + tax_category: cstr(me.frm.doc.tax_category), + item_codes: item_codes, + item_rates: item_rates + }, + callback: function(r) { + if(!r.exc) { + $.each(me.frm.doc.items || [], function(i, item) { + if(item.name && r.message.hasOwnProperty(item.name)) { + item.item_tax_template = r.message[item.name].item_tax_template; + item.item_tax_rate = r.message[item.name].item_tax_rate; + me.add_taxes_from_item_tax_template(item.item_tax_rate); + } + else { + item.item_tax_template = ""; + item.item_tax_rate = "{}"; + } + }); + } + + this.frm.refresh_fields(); + } + }); + } + }, + + add_taxes_from_item_tax_template: function(item_tax_map) { + let me = this; + + if(item_tax_map && cint(frappe.defaults.get_default("add_taxes_from_item_tax_template"))) { + if(typeof (item_tax_map) == "string") { + item_tax_map = JSON.parse(item_tax_map); + } + + $.each(item_tax_map, function(tax, rate) { + let found = (me.frm.doc.taxes || []).find(d => d.account_head === tax); + if(!found) { + let child = frappe.model.add_child(me.frm.doc, "taxes"); + child.charge_type = "On Net Total"; + child.account_head = tax; + child.rate = 0; + } + }); + } + }, + calculate_taxes: function() { var me = this; this.frm.doc.rounding_adjustment = 0; @@ -406,6 +471,11 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ let tax_detail = tax.item_wise_tax_detail; let key = item.item_code || item.item_name; + if(typeof (tax_detail) == "string") { + tax.item_wise_tax_detail = JSON.parse(tax.item_wise_tax_detail); + tax_detail = tax.item_wise_tax_detail; + } + let item_wise_tax_amount = current_tax_amount * this.frm.doc.conversion_rate; if (tax_detail && tax_detail[key]) item_wise_tax_amount += tax_detail[key][1]; diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index ad1976d2d26..ee6696b7d16 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -6,6 +6,7 @@ frappe.provide('erpnext.accounts.dimensions'); erpnext.TransactionController = erpnext.taxes_and_totals.extend({ setup: function() { this._super(); + let me = this; frappe.flags.hide_serial_batch_dialog = true; frappe.ui.form.on(this.frm.doctype + " Item", "rate", function(frm, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); @@ -43,8 +44,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ cur_frm.cscript.calculate_stock_uom_rate(frm, cdt, cdn); }); - - frappe.ui.form.on(this.frm.cscript.tax_table, "rate", function(frm, cdt, cdn) { cur_frm.cscript.calculate_taxes_and_totals(); }); @@ -121,7 +120,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ } }); - var me = this; if(this.frm.fields_dict["items"].grid.get_field('batch_no')) { this.frm.set_query("batch_no", "items", function(doc, cdt, cdn) { return me.set_query_for_batch(doc, cdt, cdn); @@ -556,6 +554,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ name: me.frm.doc.name, project: item.project || me.frm.doc.project, qty: item.qty || 1, + net_rate: item.rate, stock_qty: item.stock_qty, conversion_factor: item.conversion_factor, weight_per_unit: item.weight_per_unit, @@ -712,26 +711,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ }); }, - add_taxes_from_item_tax_template: function(item_tax_map) { - let me = this; - - if(item_tax_map && cint(frappe.defaults.get_default("add_taxes_from_item_tax_template"))) { - if(typeof (item_tax_map) == "string") { - item_tax_map = JSON.parse(item_tax_map); - } - - $.each(item_tax_map, function(tax, rate) { - let found = (me.frm.doc.taxes || []).find(d => d.account_head === tax); - if(!found) { - let child = frappe.model.add_child(me.frm.doc, "taxes"); - child.charge_type = "On Net Total"; - child.account_head = tax; - child.rate = 0; - } - }); - } - }, - serial_no: function(doc, cdt, cdn) { var me = this; var item = frappe.get_doc(cdt, cdn); @@ -835,9 +814,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ frappe.run_serially([ () => me.frm.script_manager.trigger("currency"), - () => me.update_item_tax_map(), () => me.apply_default_taxes(), - () => me.apply_pricing_rule() + () => me.apply_pricing_rule(), + () => me.calculate_taxes_and_totals() ]); } } @@ -1816,7 +1795,6 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ callback: function(r) { if(!r.exc) { item.item_tax_rate = r.message; - me.add_taxes_from_item_tax_template(item.item_tax_rate); me.calculate_taxes_and_totals(); } } @@ -1827,43 +1805,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ } }, - update_item_tax_map: function() { - var me = this; - var item_codes = []; - $.each(this.frm.doc.items || [], function(i, item) { - if(item.item_code) { - item_codes.push(item.item_code); - } - }); - if(item_codes.length) { - return this.frm.call({ - method: "erpnext.stock.get_item_details.get_item_tax_info", - args: { - company: me.frm.doc.company, - tax_category: cstr(me.frm.doc.tax_category), - item_codes: item_codes - }, - callback: function(r) { - if(!r.exc) { - $.each(me.frm.doc.items || [], function(i, item) { - if(item.item_code && r.message.hasOwnProperty(item.item_code)) { - if (!item.item_tax_template) { - item.item_tax_template = r.message[item.item_code].item_tax_template; - item.item_tax_rate = r.message[item.item_code].item_tax_rate; - } - me.add_taxes_from_item_tax_template(item.item_tax_rate); - } else { - item.item_tax_template = ""; - item.item_tax_rate = "{}"; - } - }); - me.calculate_taxes_and_totals(); - } - } - }); - } - }, is_recurring: function() { // set default values for recurring documents diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index dbac79465ee..60f468e82ec 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -128,6 +128,7 @@ class Item(WebsiteGenerator): self.validate_auto_reorder_enabled_in_stock_settings() self.cant_change() self.update_show_in_website() + self.validate_item_tax_net_rate_range() if not self.get("__islocal"): self.old_item_group = frappe.db.get_value(self.doctype, self.name, "item_group") @@ -490,6 +491,11 @@ class Item(WebsiteGenerator): if self.disabled: self.show_in_website = False + def validate_item_tax_net_rate_range(self): + for tax in self.get('taxes'): + if tax.maximum_net_rate < tax.minimum_net_rate: + frappe.throw(_("Row #{0}: Maximum Net Rate cannot be greater than Minimum Net Rate")) + def update_template_tables(self): template = frappe.get_doc("Item", self.variant_of) diff --git a/erpnext/stock/doctype/item_tax/item_tax.json b/erpnext/stock/doctype/item_tax/item_tax.json index ae36efc7e3f..fb100967f3b 100644 --- a/erpnext/stock/doctype/item_tax/item_tax.json +++ b/erpnext/stock/doctype/item_tax/item_tax.json @@ -1,4 +1,5 @@ { + "actions": [], "creation": "2013-02-22 01:28:01", "doctype": "DocType", "editable_grid": 1, @@ -6,7 +7,9 @@ "field_order": [ "item_tax_template", "tax_category", - "valid_from" + "valid_from", + "minimum_net_rate", + "maximum_net_rate" ], "fields": [ { @@ -33,11 +36,24 @@ "fieldtype": "Date", "in_list_view": 1, "label": "Valid From" + }, + { + "fieldname": "maximum_net_rate", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Maximum Net Rate" + }, + { + "fieldname": "minimum_net_rate", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Minimum Net Rate" } ], "idx": 1, "istable": 1, - "modified": "2020-06-25 01:40:28.859752", + "links": [], + "modified": "2021-06-03 13:20:06.982303", "modified_by": "Administrator", "module": "Stock", "name": "Item Tax", diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index d1dcdc21c87..6f510539a47 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -436,18 +436,22 @@ def get_barcode_data(items_list): return itemwise_barcode @frappe.whitelist() -def get_item_tax_info(company, tax_category, item_codes): +def get_item_tax_info(company, tax_category, item_codes, item_rates=None): out = {} if isinstance(item_codes, string_types): item_codes = json.loads(item_codes) + if isinstance(item_rates, string_types): + item_rates = json.loads(item_rates) + for item_code in item_codes: - if not item_code or item_code in out: + if not item_code or item_code[1] in out: continue - out[item_code] = {} - item = frappe.get_cached_doc("Item", item_code) - get_item_tax_template({"company": company, "tax_category": tax_category}, item, out[item_code]) - out[item_code]["item_tax_rate"] = get_item_tax_map(company, out[item_code].get("item_tax_template"), as_json=True) + out[item_code[1]] = {} + item = frappe.get_cached_doc("Item", item_code[0]) + args = {"company": company, "tax_category": tax_category, "net_rate": item_rates[item_code[1]]} + get_item_tax_template(args, item, out[item_code[1]]) + out[item_code[1]]["item_tax_rate"] = get_item_tax_map(company, out[item_code[1]].get("item_tax_template"), as_json=True) return out @@ -478,12 +482,13 @@ def _get_item_tax_template(args, taxes, out=None, for_validate=False): for tax in taxes: tax_company = frappe.get_value("Item Tax Template", tax.item_tax_template, 'company') - if tax.valid_from and tax_company == args['company']: + if (tax.valid_from or tax.maximum_net_rate) and tax_company == args['company']: # In purchase Invoice first preference will be given to supplier invoice date # if supplier date is not present then posting date validation_date = args.get('transaction_date') or args.get('bill_date') or args.get('posting_date') - if getdate(tax.valid_from) <= getdate(validation_date): + if getdate(tax.valid_from) <= getdate(validation_date) \ + and is_within_valid_range(args, tax): taxes_with_validity.append(tax) else: if tax_company == args['company']: @@ -502,12 +507,25 @@ def _get_item_tax_template(args, taxes, out=None, for_validate=False): if not taxes_with_validity and (not taxes_with_no_validity): return None + # do not change if already a valid template + if args.get('item_tax_template') in taxes: + return arg.get('item_tax_template') + for tax in taxes: if cstr(tax.tax_category) == cstr(args.get("tax_category")): out["item_tax_template"] = tax.item_tax_template return tax.item_tax_template return None +def is_within_valid_range(args, tax): + if not flt(tax.maximum_net_rate): + # No range specified, just ignore + return True + elif flt(tax.minimum_net_rate) <= flt(args.get('net_rate')) <= flt(tax.maximum_net_rate): + return True + + return False + @frappe.whitelist() def get_item_tax_map(company, item_tax_template, as_json=True): item_tax_map = {} From e8a78bd43d027ea36ff2902ecf48835b76109038 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 5 Jun 2021 13:16:39 +0530 Subject: [PATCH 2/4] fix: Add test cases --- .../sales_invoice/test_sales_invoice.py | 69 +++++++++++++------ erpnext/stock/doctype/item/item.py | 2 +- 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index df6d4839041..1b1bb3b18f1 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1963,6 +1963,54 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(value_details['TotInvVal'], si.base_grand_total) self.assertTrue(einvoice['EwbDtls']) + def test_item_tax_validity(self): + item = frappe.get_doc("Item", "_Test Item 2") + + if item.taxes: + item.taxes = [] + item.save() + + item.append("taxes", { + "item_tax_template": "_Test Item Tax Template 1 - _TC", + "valid_from": add_days(nowdate(), 1) + }) + + item.save() + + sales_invoice = create_sales_invoice(item = "_Test Item 2", do_not_save=1) + sales_invoice.items[0].item_tax_template = "_Test Item Tax Template 1 - _TC" + self.assertRaises(frappe.ValidationError, sales_invoice.save) + + item.taxes = [] + item.save() + + def test_item_tax_net_range(self): + item = create_item("T Shirt") + + item.set('taxes', []) + item.append("taxes", { + "item_tax_template": "_Test Account Excise Duty @ 10 - _TC", + "minimum_net_rate": 0, + "maximum_net_rate": 500 + }) + + item.append("taxes", { + "item_tax_template": "_Test Account Excise Duty @ 12 - _TC", + "minimum_net_rate": 501, + "maximum_net_rate": 1000 + }) + + item.save() + + sales_invoice = create_sales_invoice(item = "T Shirt", rate=700, do_not_submit=True) + self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 12 - _TC") + + # Apply discount + sales_invoice.apply_discount_on = 'Net Total' + sales_invoice.discount_amount = 300 + sales_invoice.save() + self.assertEqual(sales_invoice.items[0].item_tax_template, "_Test Account Excise Duty @ 10 - _TC") + def make_test_address_for_ewaybill(): if not frappe.db.exists('Address', '_Test Address for Eway bill-Billing'): address = frappe.get_doc({ @@ -2085,27 +2133,6 @@ 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 test_item_tax_validity(self): - item = frappe.get_doc("Item", "_Test Item 2") - - if item.taxes: - item.taxes = [] - item.save() - - item.append("taxes", { - "item_tax_template": "_Test Item Tax Template 1 - _TC", - "valid_from": add_days(nowdate(), 1) - }) - - item.save() - - sales_invoice = create_sales_invoice(item = "_Test Item 2", do_not_save=1) - sales_invoice.items[0].item_tax_template = "_Test Item Tax Template 1 - _TC" - self.assertRaises(frappe.ValidationError, sales_invoice.save) - - item.taxes = [] - item.save() - def create_sales_invoice(**args): si = frappe.new_doc("Sales Invoice") args = frappe._dict(args) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 60f468e82ec..0420ea7c543 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -493,7 +493,7 @@ class Item(WebsiteGenerator): def validate_item_tax_net_rate_range(self): for tax in self.get('taxes'): - if tax.maximum_net_rate < tax.minimum_net_rate: + if flt(tax.maximum_net_rate) < flt(tax.minimum_net_rate): frappe.throw(_("Row #{0}: Maximum Net Rate cannot be greater than Minimum Net Rate")) def update_template_tables(self): From 3646c301edc1380efcd0eedcd590e8124dfe90d8 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 5 Jun 2021 13:21:03 +0530 Subject: [PATCH 3/4] fix: Linting issues --- .../public/js/controllers/taxes_and_totals.js | 25 +++++++++---------- erpnext/stock/get_item_details.py | 2 +- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index ff4898eeff6..0b9d7711196 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -12,7 +12,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ if (in_list(["Sales Order", "Quotation"], item.parenttype) && item.blanket_order_rate) { effective_item_rate = item.blanket_order_rate; } - if(item.margin_type == "Percentage") { + if (item.margin_type == "Percentage") { item.rate_with_margin = flt(effective_item_rate) + flt(effective_item_rate) * ( flt(item.margin_rate_or_amount) / 100); } else { @@ -22,7 +22,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ item_rate = flt(item.rate_with_margin , precision("rate", item)); - if(item.discount_percentage){ + if (item.discount_percentage) { item.discount_amount = flt(item.rate_with_margin) * flt(item.discount_percentage) / 100; } @@ -271,14 +271,14 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ let item_codes = []; let item_rates = {}; $.each(this.frm.doc.items || [], function(i, item) { - if(item.item_code) { + if (item.item_code) { // Use combination of name and item code in case same item is added multiple times item_codes.push([item.item_code, item.name]); item_rates[item.name] = item.net_rate; } }); - if(item_codes.length) { + if (item_codes.length) { return this.frm.call({ method: "erpnext.stock.get_item_details.get_item_tax_info", args: { @@ -288,21 +288,18 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ item_rates: item_rates }, callback: function(r) { - if(!r.exc) { + if (!r.exc) { $.each(me.frm.doc.items || [], function(i, item) { - if(item.name && r.message.hasOwnProperty(item.name)) { + if (item.name && r.message.hasOwnProperty(item.name)) { item.item_tax_template = r.message[item.name].item_tax_template; item.item_tax_rate = r.message[item.name].item_tax_rate; me.add_taxes_from_item_tax_template(item.item_tax_rate); - } - else { + } else { item.item_tax_template = ""; item.item_tax_rate = "{}"; } }); } - - this.frm.refresh_fields(); } }); } @@ -311,14 +308,14 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ add_taxes_from_item_tax_template: function(item_tax_map) { let me = this; - if(item_tax_map && cint(frappe.defaults.get_default("add_taxes_from_item_tax_template"))) { - if(typeof (item_tax_map) == "string") { + if (item_tax_map && cint(frappe.defaults.get_default("add_taxes_from_item_tax_template"))) { + if (typeof (item_tax_map) == "string") { item_tax_map = JSON.parse(item_tax_map); } $.each(item_tax_map, function(tax, rate) { 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"); child.charge_type = "On Net Total"; child.account_head = tax; @@ -632,6 +629,8 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail); }); } + + this.frm.refresh_fields(); }, set_discount_amount: function() { diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 6f510539a47..746cbbf601d 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -509,7 +509,7 @@ def _get_item_tax_template(args, taxes, out=None, for_validate=False): # do not change if already a valid template if args.get('item_tax_template') in taxes: - return arg.get('item_tax_template') + return args.get('item_tax_template') for tax in taxes: if cstr(tax.tax_category) == cstr(args.get("tax_category")): From 18be767f75b9c858fa66294d037f1a9b9d2c6ace Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 6 Jun 2021 13:25:34 +0530 Subject: [PATCH 4/4] fix: Remove invalid test --- .../sales_invoice/test_sales_invoice.py | 21 ------------------- erpnext/controllers/taxes_and_totals.py | 11 +++++----- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 1b1bb3b18f1..0d61f67e528 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1963,27 +1963,6 @@ class TestSalesInvoice(unittest.TestCase): self.assertEqual(value_details['TotInvVal'], si.base_grand_total) self.assertTrue(einvoice['EwbDtls']) - def test_item_tax_validity(self): - item = frappe.get_doc("Item", "_Test Item 2") - - if item.taxes: - item.taxes = [] - item.save() - - item.append("taxes", { - "item_tax_template": "_Test Item Tax Template 1 - _TC", - "valid_from": add_days(nowdate(), 1) - }) - - item.save() - - sales_invoice = create_sales_invoice(item = "_Test Item 2", do_not_save=1) - sales_invoice.items[0].item_tax_template = "_Test Item Tax Template 1 - _TC" - self.assertRaises(frappe.ValidationError, sales_invoice.save) - - item.taxes = [] - item.save() - def test_item_tax_net_range(self): item = create_item("T Shirt") diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index 80404356346..fb22a1d608b 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -78,11 +78,12 @@ class calculate_taxes_and_totals(object): taxes = _get_item_tax_template(args, item_taxes + item_group_taxes, for_validate=True) - if item.item_tax_template not in taxes: - item.item_tax_template = taxes[0] - frappe.msgprint(_("Row {0}: Item Tax template updated as per validity and rate applied").format( - item.idx, frappe.bold(item.item_code) - )) + if taxes: + if item.item_tax_template not in taxes: + item.item_tax_template = taxes[0] + frappe.msgprint(_("Row {0}: Item Tax template updated as per validity and rate applied").format( + item.idx, frappe.bold(item.item_code) + )) def validate_conversion_rate(self): # validate conversion rate