diff --git a/erpnext/accounts/Print Format/POS Invoice/POS Invoice.txt b/erpnext/accounts/Print Format/POS Invoice/POS Invoice.txt index aab8e18491..980195642f 100644 --- a/erpnext/accounts/Print Format/POS Invoice/POS Invoice.txt +++ b/erpnext/accounts/Print Format/POS Invoice/POS Invoice.txt @@ -2,14 +2,14 @@ { "creation": "2011-12-21 11:08:55", "docstatus": 0, - "modified": "2013-09-13 17:17:47", + "modified": "2013-12-26 18:13:48", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Sales Invoice", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n \n \n \n \n \n \n \n
RECEIPT NO: DATE:
M/s
\n\n
\n\n\n", + "html": "\n\n\n\n\n\n\n\n\n \n \n \n \n \n \n \n
RECEIPT NO: DATE:
M/s
\n\n
\n\n\n", "module": "Accounts", "name": "__common__", "print_format_type": "Client", diff --git a/erpnext/accounts/Print Format/Sales Invoice Classic/Sales Invoice Classic.txt b/erpnext/accounts/Print Format/Sales Invoice Classic/Sales Invoice Classic.txt index fc99597766..09fcb91476 100644 --- a/erpnext/accounts/Print Format/Sales Invoice Classic/Sales Invoice Classic.txt +++ b/erpnext/accounts/Print Format/Sales Invoice Classic/Sales Invoice Classic.txt @@ -2,14 +2,14 @@ { "creation": "2013-04-19 13:30:27", "docstatus": 0, - "modified": "2013-08-07 20:14:53", + "modified": "2013-12-26 17:33:08", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Sales Invoice", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n\n", + "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n", "module": "Accounts", "name": "__common__", "print_format_type": "Client", diff --git a/erpnext/accounts/Print Format/Sales Invoice Modern/Sales Invoice Modern.txt b/erpnext/accounts/Print Format/Sales Invoice Modern/Sales Invoice Modern.txt index 07946f7fcc..a85a11abc8 100644 --- a/erpnext/accounts/Print Format/Sales Invoice Modern/Sales Invoice Modern.txt +++ b/erpnext/accounts/Print Format/Sales Invoice Modern/Sales Invoice Modern.txt @@ -2,14 +2,14 @@ { "creation": "2013-04-19 13:30:27", "docstatus": 0, - "modified": "2013-08-07 20:12:16", + "modified": "2013-12-26 17:33:05", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Sales Invoice", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n\n", + "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n", "module": "Accounts", "name": "__common__", "print_format_type": "Client", diff --git a/erpnext/accounts/Print Format/Sales Invoice Spartan/Sales Invoice Spartan.txt b/erpnext/accounts/Print Format/Sales Invoice Spartan/Sales Invoice Spartan.txt index 57c02fe2ec..e0850e1e9a 100644 --- a/erpnext/accounts/Print Format/Sales Invoice Spartan/Sales Invoice Spartan.txt +++ b/erpnext/accounts/Print Format/Sales Invoice Spartan/Sales Invoice Spartan.txt @@ -2,14 +2,14 @@ { "creation": "2013-04-19 13:30:27", "docstatus": 0, - "modified": "2013-08-07 19:50:51", + "modified": "2013-12-26 17:34:00", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Sales Invoice", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n\n", + "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n", "module": "Accounts", "name": "__common__", "print_format_type": "Client", diff --git a/erpnext/accounts/doctype/sales_invoice/pos.js b/erpnext/accounts/doctype/sales_invoice/pos.js index c432765981..1b14f05dc1 100644 --- a/erpnext/accounts/doctype/sales_invoice/pos.js +++ b/erpnext/accounts/doctype/sales_invoice/pos.js @@ -30,12 +30,14 @@ erpnext.POS = Class.extend({ \
\
\ - \ - \ - \ - \ - \ -
Net Total
\ +
\ + \ + \ + \ + \ + \ +
Net Total
\ +
\ \ +
\ + \ + \ + \ + \ + \ + \ +
Discount Amount\ + \ +
\ +
\
\ \ \ @@ -82,6 +96,10 @@ erpnext.POS = Class.extend({ me.refresh(); }); + this.wrapper.find('input.discount-amount').on("change", function() { + wn.model.set_value(me.frm.doctype, me.frm.docname, "discount_amount", this.value); + }); + this.call_function("delete-items", function() {me.remove_selected_item();}); this.call_function("make-payment", function() {me.make_payment();}); }, @@ -112,9 +130,9 @@ erpnext.POS = Class.extend({ }, make: function() { this.make_party(); - this.make_item_group(); - this.make_search(); this.make_barcode(); + this.make_search(); + this.make_item_group(); this.make_item_list(); }, make_party: function() { @@ -137,23 +155,23 @@ erpnext.POS = Class.extend({ me.party.toLowerCase(), this.value); }); }, - make_item_group: function() { + make_barcode: function() { var me = this; - this.item_group = wn.ui.form.make_control({ + this.barcode = wn.ui.form.make_control({ df: { - "fieldtype": "Link", - "options": "Item Group", - "label": "Item Group", - "fieldname": "pos_item_group", - "placeholder": "Item Group" + "fieldtype": "Data", + "label": "Barcode", + "fieldname": "pos_barcode", + "placeholder": "Barcode / Serial No" }, - parent: this.wrapper.find(".item-group-area"), + parent: this.wrapper.find(".barcode-area"), only_input: true, }); - this.item_group.make_input(); - this.item_group.$input.on("change", function() { - if(!me.item_group.autocomplete_open) - me.make_item_list(); + this.barcode.make_input(); + this.barcode.$input.on("keypress", function() { + if(me.barcode_timeout) + clearTimeout(me.barcode_timeout); + me.barcode_timeout = setTimeout(function() { me.add_item_thru_barcode(); }, 1000); }); }, make_search: function() { @@ -176,23 +194,23 @@ erpnext.POS = Class.extend({ me.item_timeout = setTimeout(function() { me.make_item_list(); }, 1000); }); }, - make_barcode: function() { + make_item_group: function() { var me = this; - this.barcode = wn.ui.form.make_control({ + this.item_group = wn.ui.form.make_control({ df: { - "fieldtype": "Data", - "label": "Barcode", - "fieldname": "pos_barcode", - "placeholder": "Barcode / Serial No" + "fieldtype": "Link", + "options": "Item Group", + "label": "Item Group", + "fieldname": "pos_item_group", + "placeholder": "Item Group" }, - parent: this.wrapper.find(".barcode-area"), + parent: this.wrapper.find(".item-group-area"), only_input: true, }); - this.barcode.make_input(); - this.barcode.$input.on("keypress", function() { - if(me.barcode_timeout) - clearTimeout(me.barcode_timeout); - me.barcode_timeout = setTimeout(function() { me.add_item_thru_barcode(); }, 1000); + this.item_group.make_input(); + this.item_group.$input.on("change", function() { + if(!me.item_group.autocomplete_open) + me.make_item_list(); }); }, make_item_list: function() { @@ -321,6 +339,7 @@ erpnext.POS = Class.extend({ refresh: function() { var me = this; this.party_field.set_input(this.frm.doc[this.party.toLowerCase()]); + this.wrapper.find('input.discount-amount').val(this.frm.doc.discount_amount); this.barcode.set_input(""); this.show_items_in_item_cart(); diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index 9c6a9b223d..136519e42b 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -25,7 +25,7 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte } // toggle to pos view if is_pos is 1 in user_defaults - if ((cint(wn.defaults.get_user_defaults("is_pos"))===1 || cur_frm.doc.is_pos)) { + if ((cint(wn.defaults.get_user_defaults("is_pos"))===1 || this.frm.doc.is_pos)) { if(this.frm.doc.__islocal && !this.frm.doc.amended_from && !this.frm.doc.customer) { this.frm.set_value("is_pos", 1); this.is_pos(function() { @@ -145,8 +145,8 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte me.set_default_values(); me.set_dynamic_labels(); me.calculate_taxes_and_totals(); - - if(callback_fn) callback_fn() + + if(callback_fn) callback_fn(); } } }); @@ -334,7 +334,7 @@ cur_frm.fields_dict['project_name'].get_query = function(doc, cdt, cdn) { // -------------------------------- cur_frm.set_query("income_account", "entries", function(doc) { return{ - query: "accounts.doctype.sales_invoice.sales_invoice.get_income_account", + query: "erpnext.accounts.doctype.sales_invoice.sales_invoice.get_income_account", filters: {'company': doc.company} } }); diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index f77abfe72a..4a059441fe 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -556,12 +556,12 @@ class DocType(SellingController): def make_tax_gl_entries(self, gl_entries): for tax in self.doclist.get({"parentfield": "other_charges"}): - if flt(tax.tax_amount): + if flt(tax.tax_amount_after_discount_amount): gl_entries.append( self.get_gl_dict({ "account": tax.account_head, "against": self.doc.debit_to, - "credit": flt(tax.tax_amount), + "credit": flt(tax.tax_amount_after_discount_amount), "remarks": self.doc.remarks, "cost_center": tax.cost_center }) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.txt b/erpnext/accounts/doctype/sales_invoice/sales_invoice.txt index 7de68a06ed..66f7d32c3d 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.txt +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:05", "docstatus": 0, - "modified": "2013-12-20 19:24:29", + "modified": "2014-01-03 14:52:16", "modified_by": "Administrator", "owner": "Administrator" }, @@ -455,6 +455,14 @@ "print_hide": 1, "read_only": 1 }, + { + "doctype": "DocField", + "fieldname": "discount_amount", + "fieldtype": "Currency", + "label": "Discount Amount", + "options": "Company:company:default_currency", + "print_hide": 0 + }, { "doctype": "DocField", "fieldname": "totals", diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index c68b97a3b2..709507abc1 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -44,7 +44,6 @@ class TestSalesInvoice(unittest.TestCase): def test_sales_invoice_calculation_base_currency(self): si = webnotes.bean(copy=test_records[2]) - si.run_method("calculate_taxes_and_totals") si.insert() expected_values = { @@ -136,7 +135,114 @@ class TestSalesInvoice(unittest.TestCase): self.assertEquals(si.doc.grand_total, 1627.05) self.assertEquals(si.doc.grand_total_export, 32.54) + + def test_sales_invoice_discount_amount(self): + si = webnotes.bean(copy=test_records[3]) + si.doc.discount_amount = 104.95 + si.doclist.append({ + "doctype": "Sales Taxes and Charges", + "parentfield": "other_charges", + "charge_type": "On Previous Row Amount", + "account_head": "_Test Account Service Tax - _TC", + "cost_center": "_Test Cost Center - _TC", + "description": "Service Tax", + "rate": 10, + "row_id": 8, + "idx": 9 + }) + si.insert() + + expected_values = { + "keys": ["ref_rate", "adj_rate", "export_rate", "export_amount", + "base_ref_rate", "basic_rate", "amount"], + "_Test Item Home Desktop 100": [62.5, 0, 62.5, 625.0, 50, 50, 465.37], + "_Test Item Home Desktop 200": [190.66, 0, 190.66, 953.3, 150, 150, 698.08], + } + + # check if children are saved + self.assertEquals(len(si.doclist.get({"parentfield": "entries"})), + len(expected_values)-1) + + # check if item values are calculated + for d in si.doclist.get({"parentfield": "entries"}): + for i, k in enumerate(expected_values["keys"]): + self.assertEquals(d.fields.get(k), expected_values[d.item_code][i]) + + # check net total + self.assertEquals(si.doc.net_total, 1163.45) + self.assertEquals(si.doc.net_total_export, 1578.3) + + # check tax calculation + expected_values = { + "keys": ["tax_amount", "tax_amount_after_discount_amount", "total"], + "_Test Account Excise Duty - _TC": [140, 130.31, 1293.76], + "_Test Account Education Cess - _TC": [2.8, 2.61, 1296.37], + "_Test Account S&H Education Cess - _TC": [1.4, 1.31, 1297.68], + "_Test Account CST - _TC": [27.88, 25.96, 1323.64], + "_Test Account VAT - _TC": [156.25, 145.43, 1469.07], + "_Test Account Customs Duty - _TC": [125, 116.35, 1585.42], + "_Test Account Shipping Charges - _TC": [100, 100, 1685.42], + "_Test Account Discount - _TC": [-180.33, -168.54, 1516.88], + "_Test Account Service Tax - _TC": [-18.03, -16.88, 1500] + } + + for d in si.doclist.get({"parentfield": "other_charges"}): + for i, k in enumerate(expected_values["keys"]): + self.assertEquals(d.fields.get(k), expected_values[d.account_head][i]) + self.assertEquals(si.doc.grand_total, 1500) + self.assertEquals(si.doc.grand_total_export, 1500) + + def test_discount_amount_gl_entry(self): + si = webnotes.bean(copy=test_records[3]) + si.doc.discount_amount = 104.95 + si.doclist.append({ + "doctype": "Sales Taxes and Charges", + "parentfield": "other_charges", + "charge_type": "On Previous Row Amount", + "account_head": "_Test Account Service Tax - _TC", + "cost_center": "_Test Cost Center - _TC", + "description": "Service Tax", + "rate": 10, + "row_id": 8, + "idx": 9 + }) + si.insert() + si.submit() + + gl_entries = webnotes.conn.sql("""select account, debit, credit + from `tabGL Entry` where voucher_type='Sales Invoice' and voucher_no=%s + order by account asc""", si.doc.name, as_dict=1) + + self.assertTrue(gl_entries) + + expected_values = sorted([ + [si.doc.debit_to, 1500, 0.0], + [test_records[3][1]["income_account"], 0.0, 1163.45], + [test_records[3][3]["account_head"], 0.0, 130.31], + [test_records[3][4]["account_head"], 0.0, 2.61], + [test_records[3][5]["account_head"], 0.0, 1.31], + [test_records[3][6]["account_head"], 0.0, 25.96], + [test_records[3][7]["account_head"], 0.0, 145.43], + [test_records[3][8]["account_head"], 0.0, 116.35], + [test_records[3][9]["account_head"], 0.0, 100], + [test_records[3][10]["account_head"], 168.54, 0.0], + ["_Test Account Service Tax - _TC", 16.88, 0.0], + ]) + + for i, gle in enumerate(gl_entries): + self.assertEquals(expected_values[i][0], gle.account) + self.assertEquals(expected_values[i][1], gle.debit) + self.assertEquals(expected_values[i][2], gle.credit) + + # cancel + si.cancel() + + gle = webnotes.conn.sql("""select * from `tabGL Entry` + where voucher_type='Sales Invoice' and voucher_no=%s""", si.doc.name) + + self.assertFalse(gle) + def test_inclusive_rate_validations(self): si = webnotes.bean(copy=test_records[2]) for i, tax in enumerate(si.doclist.get({"parentfield": "other_charges"})): @@ -148,16 +254,15 @@ class TestSalesInvoice(unittest.TestCase): si.doclist[i].included_in_print_rate = 1 # tax type "Actual" cannot be inclusive - self.assertRaises(webnotes.ValidationError, si.run_method, "calculate_taxes_and_totals") + self.assertRaises(webnotes.ValidationError, si.insert) # taxes above included type 'On Previous Row Total' should also be included si.doclist[3].included_in_print_rate = 0 - self.assertRaises(webnotes.ValidationError, si.run_method, "calculate_taxes_and_totals") + self.assertRaises(webnotes.ValidationError, si.insert) def test_sales_invoice_calculation_base_currency_with_tax_inclusive_price(self): # prepare si = webnotes.bean(copy=test_records[3]) - si.run_method("calculate_taxes_and_totals") si.insert() expected_values = { @@ -195,7 +300,7 @@ class TestSalesInvoice(unittest.TestCase): for d in si.doclist.get({"parentfield": "other_charges"}): for i, k in enumerate(expected_values["keys"]): - self.assertEquals(flt(d.fields.get(k), 6), expected_values[d.account_head][i]) + self.assertEquals(d.fields.get(k), expected_values[d.account_head][i]) self.assertEquals(si.doc.grand_total, 1622.98) self.assertEquals(si.doc.grand_total_export, 1622.98) @@ -211,7 +316,6 @@ class TestSalesInvoice(unittest.TestCase): si.doclist[2].adj_rate = 20 si.doclist[9].rate = 5000 - si.run_method("calculate_taxes_and_totals") si.insert() expected_values = { @@ -249,7 +353,7 @@ class TestSalesInvoice(unittest.TestCase): for d in si.doclist.get({"parentfield": "other_charges"}): for i, k in enumerate(expected_values["keys"]): - self.assertEquals(flt(d.fields.get(k), 6), expected_values[d.account_head][i]) + self.assertEquals(d.fields.get(k), expected_values[d.account_head][i]) self.assertEquals(si.doc.grand_total, 65205.16) self.assertEquals(si.doc.grand_total_export, 1304.1) @@ -403,7 +507,6 @@ class TestSalesInvoice(unittest.TestCase): pr = webnotes.bean(copy=pr_test_records[0]) pr.doc.naming_series = "_T-Purchase Receipt-" pr.doclist[1].warehouse = "_Test Warehouse No Account - _TC" - pr.run_method("calculate_taxes_and_totals") pr.insert() pr.submit() @@ -448,7 +551,7 @@ class TestSalesInvoice(unittest.TestCase): self.assertFalse(gle) set_perpetual_inventory(0) - def test_sales_invoice_gl_entry_with_aii_no_item_code(self): + def test_sales_invoice_gl_entry_with_aii_no_item_code(self): self.clear_stock_account_balance() set_perpetual_inventory() @@ -508,7 +611,6 @@ class TestSalesInvoice(unittest.TestCase): as pr_test_records pr = webnotes.bean(copy=pr_test_records[0]) pr.doc.naming_series = "_T-Purchase Receipt-" - pr.run_method("calculate_taxes_and_totals") pr.insert() pr.submit() diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.txt b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.txt index 49df5f7291..8bb154cb7f 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.txt +++ b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.txt @@ -2,7 +2,7 @@ { "creation": "2013-04-24 11:39:32", "docstatus": 0, - "modified": "2013-12-31 17:51:47", + "modified": "2014-01-03 15:04:25", "modified_by": "Administrator", "owner": "Administrator" }, @@ -132,12 +132,21 @@ "report_hide": 1, "width": "150px" }, + { + "doctype": "DocField", + "fieldname": "tax_amount_after_discount_amount", + "fieldtype": "Currency", + "hidden": 1, + "label": "Tax Amount After Discount Amount", + "options": "Company:company:default_currency", + "read_only": 1 + }, { "doctype": "DocField", "fieldname": "item_wise_tax_detail", "fieldtype": "Small Text", "hidden": 1, - "label": "Item Wise Tax Detail ", + "label": "Item Wise Tax Detail", "oldfieldname": "item_wise_tax_detail", "oldfieldtype": "Small Text", "read_only": 1 diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js b/erpnext/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js index 0cdead9030..0e9b3db6c0 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js +++ b/erpnext/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js @@ -19,6 +19,10 @@ cur_frm.pformat.net_total_export = function(doc) { return ''; } +cur_frm.pformat.discount_amount = function(doc) { + return ''; +} + cur_frm.pformat.grand_total_export = function(doc) { return ''; } @@ -33,10 +37,10 @@ cur_frm.pformat.in_words_export = function(doc) { cur_frm.pformat.other_charges= function(doc){ //function to make row of table - var make_row = function(title,val,bold){ + var make_row = function(title, val, bold){ var bstart = ''; var bend = ''; - return '' - +'' + return '' + +'' +'' } @@ -52,7 +56,7 @@ cur_frm.pformat.other_charges= function(doc){ out =''; if (!doc.print_without_amount) { - var cl = getchildren('Sales Taxes and Charges',doc.name,'other_charges'); + var cl = getchildren('Sales Taxes and Charges', doc.name, 'other_charges'); // outer table var out='
'+(bold?bstart:'')+title+(bold?bend:'')+''+format_currency(val, doc.currency)+'
' + (bold?bstart:'') + title + (bold?bend:'') + '' + format_currency(val, doc.currency) + '
'; @@ -60,6 +64,7 @@ cur_frm.pformat.other_charges= function(doc){ // main table out +=''; + if(!print_hide('net_total_export')) { out += make_row('Net Total', doc.net_total_export, 1); } @@ -68,26 +73,31 @@ cur_frm.pformat.other_charges= function(doc){ if(cl.length){ for(var i=0;i' + out += '' } - out +='
' + doc.in_words_export + '
'; + out += '
'; } return out; } @@ -99,7 +109,7 @@ cur_frm.cscript.charge_type = function(doc, cdt, cdn) { d.charge_type = ''; } validated = false; - refresh_field('charge_type',d.name,'other_charges'); + refresh_field('charge_type', d.name, 'other_charges'); cur_frm.cscript.row_id(doc, cdt, cdn); cur_frm.cscript.rate(doc, cdt, cdn); cur_frm.cscript.tax_amount(doc, cdt, cdn); @@ -122,7 +132,7 @@ cur_frm.cscript.row_id = function(doc, cdt, cdn) { } } validated = false; - refresh_field('row_id',d.name,'other_charges'); + refresh_field('row_id', d.name, 'other_charges'); } /*---------------------- Get rate if account_head has account_type as TAX or CHARGEABLE-------------------------------------*/ @@ -152,7 +162,7 @@ cur_frm.cscript.rate = function(doc, cdt, cdn) { d.rate = ''; } validated = false; - refresh_field('rate',d.name,'other_charges'); + refresh_field('rate', d.name, 'other_charges'); } cur_frm.cscript.tax_amount = function(doc, cdt, cdn) { @@ -166,5 +176,5 @@ cur_frm.cscript.tax_amount = function(doc, cdt, cdn) { d.tax_amount = ''; } validated = false; - refresh_field('tax_amount',d.name,'other_charges'); + refresh_field('tax_amount', d.name, 'other_charges'); }; \ No newline at end of file diff --git a/erpnext/accounts/report/sales_register/sales_register.py b/erpnext/accounts/report/sales_register/sales_register.py index 49b914e4a3..8fab6a9d97 100644 --- a/erpnext/accounts/report/sales_register/sales_register.py +++ b/erpnext/accounts/report/sales_register/sales_register.py @@ -79,7 +79,7 @@ def get_columns(invoice_list): tax_accounts = webnotes.conn.sql_list("""select distinct account_head from `tabSales Taxes and Charges` where parenttype = 'Sales Invoice' - and docstatus = 1 and ifnull(tax_amount, 0) != 0 + and docstatus = 1 and ifnull(tax_amount_after_discount_amount, 0) != 0 and parent in (%s) order by account_head""" % ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list])) @@ -126,7 +126,8 @@ def get_invoice_income_map(invoice_list): return invoice_income_map def get_invoice_tax_map(invoice_list, invoice_income_map, income_accounts): - tax_details = webnotes.conn.sql("""select parent, account_head, sum(tax_amount) as tax_amount + tax_details = webnotes.conn.sql("""select parent, account_head, + sum(tax_amount_after_discount_amount) as tax_amount from `tabSales Taxes and Charges` where parent in (%s) group by parent, account_head""" % ', '.join(['%s']*len(invoice_list)), tuple([inv.name for inv in invoice_list]), as_dict=1) diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.js b/erpnext/buying/doctype/purchase_common/purchase_common.js index cc24925905..f528f6cf1b 100644 --- a/erpnext/buying/doctype/purchase_common/purchase_common.js +++ b/erpnext/buying/doctype/purchase_common/purchase_common.js @@ -360,6 +360,14 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ }); } } + + if(this.frm.tax_doclist.length) { + if(!wn.meta.get_docfield(this.frm.tax_doclist[0].doctype, "tax_amount_after_discount_amount", this.frm.doctype)) { + $.each(this.frm.tax_doclist, function(i, tax) { + delete tax["tax_amount_after_discount_amount"]; + }); + } + } }, calculate_outstanding_amount: function() { diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 3659f6ddee..eafb3f34f0 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -1,7 +1,6 @@ # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors # License: GNU General Public License v3. See license.txt - from __future__ import unicode_literals import unittest import webnotes diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index d48a7a6d17..e7393eb735 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -133,6 +133,12 @@ class AccountsController(TransactionBase): self.doclist.append(tax) def calculate_taxes_and_totals(self): + self.discount_amount_applied = False + self._calculate_taxes_and_totals() + if self.meta.get_field(self.doc.doctype, "discount_amount"): + self.apply_discount_amount() + + def _calculate_taxes_and_totals(self): # validate conversion rate company_currency = get_company_currency(self.doc.company) if not self.doc.currency or self.doc.currency == company_currency: @@ -141,7 +147,7 @@ class AccountsController(TransactionBase): else: validate_conversion_rate(self.doc.currency, self.doc.conversion_rate, self.meta.get_label("conversion_rate"), self.doc.company) - + self.doc.conversion_rate = flt(self.doc.conversion_rate) self.item_doclist = self.doclist.get({"parentfield": self.fname}) self.tax_doclist = self.doclist.get({"parentfield": self.other_fname}) @@ -157,17 +163,19 @@ class AccountsController(TransactionBase): self.calculate_totals() self._cleanup() - # TODO - # print format: show net_total_export instead of net_total - def initialize_taxes(self): for tax in self.tax_doclist: tax.item_wise_tax_detail = {} - for fieldname in ["tax_amount", "total", - "tax_amount_for_current_item", "grand_total_for_current_item", - "tax_fraction_for_current_item", "grand_total_fraction_for_current_item"]: - tax.fields[fieldname] = 0.0 - + tax_fields = ["total", "tax_amount_after_discount_amount", + "tax_amount_for_current_item", "grand_total_for_current_item", + "tax_fraction_for_current_item", "grand_total_fraction_for_current_item"] + + if not self.discount_amount_applied: + tax_fields.append("tax_amount") + + for fieldname in tax_fields: + tax.fields[fieldname] = 0.0 + self.validate_on_previous_row(tax) self.validate_inclusive_tax(tax) self.round_floats_in(tax) @@ -215,39 +223,44 @@ class AccountsController(TransactionBase): "charge_type": tax.charge_type, }, raise_exception=True) elif tax.charge_type == "On Previous Row Amount" and \ - not cint(self.tax_doclist[tax.row_id - 1].included_in_print_rate): + not cint(self.tax_doclist[cint(tax.row_id) - 1].included_in_print_rate): # referred row should also be inclusive _on_previous_row_error(tax.row_id) elif tax.charge_type == "On Previous Row Total" and \ - not all([cint(t.included_in_print_rate) for t in self.tax_doclist[:tax.row_id - 1]]): + not all([cint(t.included_in_print_rate) for t in self.tax_doclist[:cint(tax.row_id) - 1]]): # all rows about the reffered tax should be inclusive _on_previous_row_error("1 - %d" % (tax.row_id,)) def calculate_taxes(self): - for item in self.item_doclist: + # maintain actual tax rate based on idx + actual_tax_dict = dict([[tax.idx, tax.rate] for tax in self.tax_doclist + if tax.charge_type == "Actual"]) + + for n, item in enumerate(self.item_doclist): item_tax_map = self._load_item_tax_rate(item.item_tax_rate) for i, tax in enumerate(self.tax_doclist): # tax_amount represents the amount of tax for the current step current_tax_amount = self.get_current_tax_amount(item, tax, item_tax_map) + + # Adjust divisional loss to the last item + if tax.charge_type == "Actual": + actual_tax_dict[tax.idx] -= current_tax_amount + if n == len(self.item_doclist) - 1: + current_tax_amount += actual_tax_dict[tax.idx] if hasattr(self, "set_item_tax_amount"): self.set_item_tax_amount(item, tax, current_tax_amount) - # case when net total is 0 but there is an actual type charge - # in this case add the actual amount to tax.tax_amount - # and tax.grand_total_for_current_item for the first such iteration - if tax.charge_type=="Actual" and \ - not (current_tax_amount or self.doc.net_total or tax.tax_amount): - zero_net_total_adjustment = flt(tax.rate, self.precision("tax_amount", tax)) - current_tax_amount += zero_net_total_adjustment - # store tax_amount for current item as it will be used for # charge type = 'On Previous Row Amount' tax.tax_amount_for_current_item = current_tax_amount # accumulate tax amount into tax.tax_amount - tax.tax_amount += current_tax_amount + if not self.discount_amount_applied: + tax.tax_amount += current_tax_amount + + tax.tax_amount_after_discount_amount += current_tax_amount if tax.category: # if just for valuation, do not add the tax amount in total @@ -260,17 +273,36 @@ class AccountsController(TransactionBase): # note: grand_total_for_current_item contains the contribution of # item's amount, previously applied tax and the current tax on that item if i==0: - tax.grand_total_for_current_item = flt(item.amount + - current_tax_amount, self.precision("total", tax)) - + tax.grand_total_for_current_item = flt(item.amount + current_tax_amount, + self.precision("total", tax)) else: tax.grand_total_for_current_item = \ - flt(self.tax_doclist[i-1].grand_total_for_current_item + + flt(self.tax_doclist[i-1].grand_total_for_current_item + current_tax_amount, self.precision("total", tax)) # in tax.total, accumulate grand total of each item tax.total += tax.grand_total_for_current_item - + + # set precision in the last item iteration + if n == len(self.item_doclist) - 1: + self.round_off_totals(tax) + + # adjust Discount Amount loss in last tax iteration + if i == (len(self.tax_doclist) - 1) and self.discount_amount_applied: + self.adjust_discount_amount_loss(tax) + + def round_off_totals(self, tax): + tax.total = flt(tax.total, self.precision("total", tax)) + tax.tax_amount = flt(tax.tax_amount, self.precision("tax_amount", tax)) + tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount, + self.precision("tax_amount", tax)) + + def adjust_discount_amount_loss(self, tax): + discount_amount_loss = self.doc.grand_total - flt(self.doc.discount_amount) - tax.total + tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount + + discount_amount_loss, self.precision("tax_amount", tax)) + tax.total = flt(tax.total + discount_amount_loss, self.precision("total", tax)) + def get_current_tax_amount(self, item, tax, item_tax_map): tax_rate = self._get_tax_rate(tax, item_tax_map) current_tax_amount = 0.0 @@ -289,9 +321,9 @@ class AccountsController(TransactionBase): elif tax.charge_type == "On Previous Row Total": current_tax_amount = (tax_rate / 100.0) * \ self.tax_doclist[cint(tax.row_id) - 1].grand_total_for_current_item - + current_tax_amount = flt(current_tax_amount, self.precision("tax_amount", tax)) - + # store tax breakup for each item key = item.item_code or item.item_name if tax.item_wise_tax_detail.get(key): diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index 40de926ea0..f630f5ae83 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -5,7 +5,6 @@ from __future__ import unicode_literals import webnotes from webnotes import _, msgprint from webnotes.utils import flt, _round - from erpnext.buying.utils import get_item_details from erpnext.setup.utils import get_company_currency @@ -148,7 +147,7 @@ class BuyingController(StockController): def _cleanup(self): super(BuyingController, self)._cleanup() - # except in purchase invoice, rate field is purchase_rate + # except in purchase invoice, rate field is purchase_rate # reset fieldname of rate if self.doc.doctype != "Purchase Invoice": df = self.meta.get_field("rate", parentfield=self.fname) @@ -161,6 +160,10 @@ class BuyingController(StockController): if not self.meta.get_field("item_tax_amount", parentfield=self.fname): for item in self.item_doclist: del item.fields["item_tax_amount"] + + if not self.meta.get_field("tax_amount_after_discount_amount", parentfield=self.other_fname): + for tax in self.tax_doclist: + del tax.fields["tax_amount_after_discount_amount"] def set_item_tax_amount(self, item, tax, current_tax_amount): """ diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index f950f28181..04bcfaeb04 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -121,7 +121,7 @@ class SellingController(StockController): cumulated_tax_fraction += tax.tax_fraction_for_current_item - if cumulated_tax_fraction: + if cumulated_tax_fraction and not self.discount_amount_applied: item.amount = flt((item.export_amount * self.doc.conversion_rate) / (1 + cumulated_tax_fraction), self.precision("amount", item)) @@ -158,22 +158,23 @@ class SellingController(StockController): return current_tax_fraction def calculate_item_values(self): - for item in self.item_doclist: - self.round_floats_in(item) - - if item.adj_rate == 100: - item.export_rate = 0 - elif not item.export_rate: - item.export_rate = flt(item.ref_rate * (1.0 - (item.adj_rate / 100.0)), - self.precision("export_rate", item)) - - item.export_amount = flt(item.export_rate * item.qty, - self.precision("export_amount", item)) + if not self.discount_amount_applied: + for item in self.item_doclist: + self.round_floats_in(item) + + if item.adj_rate == 100: + item.export_rate = 0 + elif not item.export_rate: + item.export_rate = flt(item.ref_rate * (1.0 - (item.adj_rate / 100.0)), + self.precision("export_rate", item)) + + item.export_amount = flt(item.export_rate * item.qty, + self.precision("export_amount", item)) + + self._set_in_company_currency(item, "ref_rate", "base_ref_rate") + self._set_in_company_currency(item, "export_rate", "basic_rate") + self._set_in_company_currency(item, "export_amount", "amount") - self._set_in_company_currency(item, "ref_rate", "base_ref_rate") - self._set_in_company_currency(item, "export_rate", "basic_rate") - self._set_in_company_currency(item, "export_amount", "amount") - def calculate_net_total(self): self.doc.net_total = self.doc.net_total_export = 0.0 @@ -191,12 +192,40 @@ class SellingController(StockController): self.doc.other_charges_total = flt(self.doc.grand_total - self.doc.net_total, self.precision("other_charges_total")) - self.doc.other_charges_total_export = flt(self.doc.grand_total_export - self.doc.net_total_export, - self.precision("other_charges_total_export")) + self.doc.other_charges_total_export = flt(self.doc.grand_total_export - + self.doc.net_total_export + flt(self.doc.discount_amount), self.precision("other_charges_total_export")) self.doc.rounded_total = _round(self.doc.grand_total) self.doc.rounded_total_export = _round(self.doc.grand_total_export) - + + def apply_discount_amount(self): + if self.doc.discount_amount: + grand_total_for_discount_amount = self.get_grand_total_for_discount_amount() + + if grand_total_for_discount_amount: + # calculate item amount after Discount Amount + for item in self.item_doclist: + distributed_amount = flt(self.doc.discount_amount) * item.amount / grand_total_for_discount_amount + item.amount = flt(item.amount - distributed_amount, self.precision("amount", item)) + + self.discount_amount_applied = True + self._calculate_taxes_and_totals() + + def get_grand_total_for_discount_amount(self): + actual_taxes_dict = {} + + for tax in self.tax_doclist: + if tax.charge_type == "Actual": + actual_taxes_dict.setdefault(tax.idx, tax.tax_amount) + elif tax.row_id in actual_taxes_dict: + actual_tax_amount = flt(actual_taxes_dict.get(tax.row_id, 0)) * \ + flt(tax.rate) / 100 + actual_taxes_dict.setdefault(tax.idx, actual_tax_amount) + + grand_total_for_discount_amount = flt(self.doc.grand_total - sum(actual_taxes_dict.values()), + self.precision("grand_total")) + return grand_total_for_discount_amount + def calculate_outstanding_amount(self): # NOTE: # write_off_amount is only for POS Invoice diff --git a/erpnext/patches.txt b/erpnext/patches.txt index c1ab098298..f39e214245 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -1,3 +1,21 @@ erpnext.patches.4_0.update_user_properties erpnext.patches.4_0.move_warehouse_user_to_restrictions -erpnext.patches.4_0.new_permissions \ No newline at end of file +erpnext.patches.4_0.new_permissions + +execute:webnotes.reload_doc('accounts', 'doctype', 'sales_invoice') # 2014-01-03 +execute:webnotes.reload_doc('selling', 'doctype', 'sales_order') # 2014-01-03 +execute:webnotes.reload_doc('selling', 'doctype', 'quotation') # 2014-01-03 +execute:webnotes.reload_doc('stock', 'doctype', 'delivery_note') # 2014-01-03 +execute:webnotes.reload_doc('accounts', 'Print Format', 'POS Invoice') # 2014-01-03 +execute:webnotes.reload_doc('accounts', 'Print Format', 'Sales Invoice Classic') # 2014-01-03 +execute:webnotes.reload_doc('accounts', 'Print Format', 'Sales Invoice Modern') # 2014-01-03 +execute:webnotes.reload_doc('accounts', 'Print Format', 'Sales Invoice Spartan') # 2014-01-03 +execute:webnotes.reload_doc('selling', 'Print Format', 'Quotation Classic') # 2014-01-03 +execute:webnotes.reload_doc('selling', 'Print Format', 'Quotation Modern') # 2014-01-03 +execute:webnotes.reload_doc('selling', 'Print Format', 'Quotation Spartan') # 2014-01-03 +execute:webnotes.reload_doc('selling', 'Print Format', 'Sales Order Classic') # 2014-01-03 +execute:webnotes.reload_doc('selling', 'Print Format', 'Sales Order Modern') # 2014-01-03 +execute:webnotes.reload_doc('selling', 'Print Format', 'Sales Order Spartan') # 2014-01-03 +execute:webnotes.reload_doc('stock', 'Print Format', 'Delivery Note Classic') # 2014-01-03 +execute:webnotes.reload_doc('stock', 'Print Format', 'Delivery Note Modern') # 2014-01-03 +execute:webnotes.reload_doc('stock', 'Print Format', 'Delivery Note Spartan') # 2014-01-03 \ No newline at end of file diff --git a/erpnext/patches/patch_list.py b/erpnext/patches/patch_list.py index e455913f59..002e3c7084 100644 --- a/erpnext/patches/patch_list.py +++ b/erpnext/patches/patch_list.py @@ -172,18 +172,18 @@ patch_list = [ "patches.july_2013.p05_custom_doctypes_in_list_view", "patches.july_2013.p06_same_sales_rate", "patches.july_2013.p07_repost_billed_amt_in_sales_cycle", - "execute:webnotes.reload_doc('accounts', 'Print Format', 'Sales Invoice Classic') # 2013-07-22", - "execute:webnotes.reload_doc('accounts', 'Print Format', 'Sales Invoice Modern') # 2013-07-22", - "execute:webnotes.reload_doc('accounts', 'Print Format', 'Sales Invoice Spartan') # 2013-07-22", - "execute:webnotes.reload_doc('selling', 'Print Format', 'Quotation Classic') # 2013-07-22", - "execute:webnotes.reload_doc('selling', 'Print Format', 'Quotation Modern') # 2013-07-22", - "execute:webnotes.reload_doc('selling', 'Print Format', 'Quotation Spartan') # 2013-07-22", - "execute:webnotes.reload_doc('selling', 'Print Format', 'Sales Order Classic') # 2013-07-22", - "execute:webnotes.reload_doc('selling', 'Print Format', 'Sales Order Modern') # 2013-07-22", - "execute:webnotes.reload_doc('selling', 'Print Format', 'Sales Order Spartan') # 2013-07-22", - "execute:webnotes.reload_doc('stock', 'Print Format', 'Delivery Note Classic') # 2013-07-22", - "execute:webnotes.reload_doc('stock', 'Print Format', 'Delivery Note Modern') # 2013-07-22", - "execute:webnotes.reload_doc('stock', 'Print Format', 'Delivery Note Spartan') # 2013-07-22", + "execute:webnotes.reload_doc('accounts', 'Print Format', 'Sales Invoice Classic') # 2013-12-26", + "execute:webnotes.reload_doc('accounts', 'Print Format', 'Sales Invoice Modern') # 2013-12-26", + "execute:webnotes.reload_doc('accounts', 'Print Format', 'Sales Invoice Spartan') # 2013-12-26", + "execute:webnotes.reload_doc('selling', 'Print Format', 'Quotation Classic') # 2013-12-26", + "execute:webnotes.reload_doc('selling', 'Print Format', 'Quotation Modern') # 2013-12-26", + "execute:webnotes.reload_doc('selling', 'Print Format', 'Quotation Spartan') # 2013-12-26", + "execute:webnotes.reload_doc('selling', 'Print Format', 'Sales Order Classic') # 2013-12-26", + "execute:webnotes.reload_doc('selling', 'Print Format', 'Sales Order Modern') # 2013-12-26", + "execute:webnotes.reload_doc('selling', 'Print Format', 'Sales Order Spartan') # 2013-12-26", + "execute:webnotes.reload_doc('stock', 'Print Format', 'Delivery Note Classic') # 2013-12-26", + "execute:webnotes.reload_doc('stock', 'Print Format', 'Delivery Note Modern') # 2013-12-26", + "execute:webnotes.reload_doc('stock', 'Print Format', 'Delivery Note Spartan') # 2013-12-26", "patches.july_2013.p08_custom_print_format_net_total_export", "patches.july_2013.p09_remove_website_pyc", "patches.july_2013.p10_change_partner_user_to_website_user", @@ -262,4 +262,9 @@ patch_list = [ "execute:webnotes.delete_doc('DocType', 'Warehouse Type')", "patches.1312.p01_delete_old_stock_reports", "patches.1312.p02_update_item_details_in_item_price", + "execute:webnotes.reload_doc('accounts', 'Print Format', 'POS Invoice') # 2013-12-26", + "execute:webnotes.reload_doc('accounts', 'doctype', 'sales_invoice') # 2013-12-26", + "execute:webnotes.reload_doc('selling', 'doctype', 'sales_order') # 2013-12-26", + "execute:webnotes.reload_doc('selling', 'doctype', 'quotation') # 2013-12-26", + "execute:webnotes.reload_doc('stock', 'doctype', 'delivery_note') # 2013-12-26", ] \ No newline at end of file diff --git a/erpnext/public/js/transaction.js b/erpnext/public/js/transaction.js index 5b48820c9c..7db7aef51d 100644 --- a/erpnext/public/js/transaction.js +++ b/erpnext/public/js/transaction.js @@ -511,10 +511,17 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ }, calculate_taxes_and_totals: function() { + this.discount_amount_applied = false; + this._calculate_taxes_and_totals(); + if (wn.meta.get_docfield(this.frm.doc.doctype, "discount_amount")) + this.apply_discount_amount(); + }, + + _calculate_taxes_and_totals: function() { this.validate_conversion_rate(); this.frm.item_doclist = this.get_item_doclist(); this.frm.tax_doclist = this.get_tax_doclist(); - + this.calculate_item_values(); this.initialize_taxes(); this.determine_exclusive_rate && this.determine_exclusive_rate(); @@ -522,18 +529,23 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ this.calculate_taxes(); this.calculate_totals(); this._cleanup(); - + this.show_item_wise_taxes(); }, initialize_taxes: function() { var me = this; + $.each(this.frm.tax_doclist, function(i, tax) { tax.item_wise_tax_detail = {}; - $.each(["tax_amount", "total", + tax_fields = ["total", "tax_amount_after_discount_amount", "tax_amount_for_current_item", "grand_total_for_current_item", - "tax_fraction_for_current_item", "grand_total_fraction_for_current_item"], - function(i, fieldname) { tax[fieldname] = 0.0 }); + "tax_fraction_for_current_item", "grand_total_fraction_for_current_item"] + + if (!me.discount_amount_applied) + tax_fields.push("tax_amount"); + + $.each(tax_fields, function(i, fieldname) { tax[fieldname] = 0.0 }); me.validate_on_previous_row(tax); me.validate_inclusive_tax(tax); @@ -543,31 +555,41 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ calculate_taxes: function() { var me = this; + var actual_tax_dict = {}; + // maintain actual tax rate based on idx + $.each(this.frm.tax_doclist, function(i, tax) { + if (tax.charge_type == "Actual") { + actual_tax_dict[tax.idx] = flt(tax.rate); + } + }); + $.each(this.frm.item_doclist, function(n, item) { var item_tax_map = me._load_item_tax_rate(item.item_tax_rate); - + $.each(me.frm.tax_doclist, function(i, tax) { // tax_amount represents the amount of tax for the current step var current_tax_amount = me.get_current_tax_amount(item, tax, item_tax_map); - me.set_item_tax_amount && me.set_item_tax_amount(item, tax, current_tax_amount); - - // case when net total is 0 but there is an actual type charge - // in this case add the actual amount to tax.tax_amount - // and tax.grand_total_for_current_item for the first such iteration - if(tax.charge_type == "Actual" && - !(current_tax_amount || me.frm.doc.net_total || tax.tax_amount)) { - var zero_net_total_adjustment = flt(tax.rate, precision("tax_amount", tax)); - current_tax_amount += zero_net_total_adjustment; + // Adjust divisional loss to the last item + if (tax.charge_type == "Actual") { + actual_tax_dict[tax.idx] -= current_tax_amount; + if (n == me.frm.item_doclist.length - 1) { + current_tax_amount += actual_tax_dict[tax.idx] } - + } + + me.set_item_tax_amount && me.set_item_tax_amount(item, tax, current_tax_amount); + // store tax_amount for current item as it will be used for // charge type = 'On Previous Row Amount' tax.tax_amount_for_current_item = current_tax_amount; // accumulate tax amount into tax.tax_amount - tax.tax_amount += current_tax_amount; + if (!me.discount_amount_applied) + tax.tax_amount += current_tax_amount; + + tax.tax_amount_after_discount_amount += current_tax_amount; // for buying if(tax.category) { @@ -592,9 +614,32 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ // in tax.total, accumulate grand total for each item tax.total += tax.grand_total_for_current_item; + + // set precision in the last item iteration + if (n == me.frm.item_doclist.length - 1) { + me.round_off_totals(tax); + + // adjust Discount Amount loss in last tax iteration + if ((i == me.frm.tax_doclist.length - 1) && me.discount_amount_applied) + me.adjust_discount_amount_loss(tax); + } }); }); }, + + round_off_totals: function(tax) { + tax.total = flt(tax.total, precision("total", tax)); + tax.tax_amount = flt(tax.tax_amount, precision("tax_amount", tax)); + tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount, + precision("tax_amount", tax)); + }, + + adjust_discount_amount_loss: function(tax) { + var discount_amount_loss = this.frm.doc.grand_total - flt(this.frm.doc.discount_amount) - tax.total; + tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount + + discount_amount_loss, precision("tax_amount", tax)); + tax.total = flt(tax.total + discount_amount_loss, precision("total", tax)); + }, get_current_tax_amount: function(item, tax, item_tax_map) { var tax_rate = this._get_tax_rate(tax, item_tax_map); @@ -617,9 +662,8 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ } else if(tax.charge_type == "On Previous Row Total") { current_tax_amount = (tax_rate / 100.0) * this.frm.tax_doclist[cint(tax.row_id) - 1].grand_total_for_current_item; - } - + current_tax_amount = flt(current_tax_amount, precision("tax_amount", tax)); // store tax breakup for each item diff --git a/erpnext/selling/Print Format/Quotation Classic/Quotation Classic.txt b/erpnext/selling/Print Format/Quotation Classic/Quotation Classic.txt index e7588c4522..05c3c598ca 100644 --- a/erpnext/selling/Print Format/Quotation Classic/Quotation Classic.txt +++ b/erpnext/selling/Print Format/Quotation Classic/Quotation Classic.txt @@ -2,14 +2,14 @@ { "creation": "2013-04-19 13:30:51", "docstatus": 0, - "modified": "2013-08-07 19:55:11", + "modified": "2013-12-26 17:45:37", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Quotation", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n\n", + "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n", "module": "Selling", "name": "__common__", "print_format_type": "Client", diff --git a/erpnext/selling/Print Format/Quotation Modern/Quotation Modern.txt b/erpnext/selling/Print Format/Quotation Modern/Quotation Modern.txt index 20d380dcbf..35850e62eb 100644 --- a/erpnext/selling/Print Format/Quotation Modern/Quotation Modern.txt +++ b/erpnext/selling/Print Format/Quotation Modern/Quotation Modern.txt @@ -2,14 +2,14 @@ { "creation": "2013-04-19 13:30:51", "docstatus": 0, - "modified": "2013-08-07 20:12:11", + "modified": "2013-12-26 17:45:15", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Quotation", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n\n", + "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n", "module": "Selling", "name": "__common__", "print_format_type": "Client", diff --git a/erpnext/selling/Print Format/Quotation Spartan/Quotation Spartan.txt b/erpnext/selling/Print Format/Quotation Spartan/Quotation Spartan.txt index c5b4cb92b3..3b4452666b 100644 --- a/erpnext/selling/Print Format/Quotation Spartan/Quotation Spartan.txt +++ b/erpnext/selling/Print Format/Quotation Spartan/Quotation Spartan.txt @@ -2,14 +2,14 @@ { "creation": "2013-04-19 13:30:51", "docstatus": 0, - "modified": "2013-08-07 19:53:01", + "modified": "2013-12-26 17:45:50", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Quotation", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n\n", + "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n", "module": "Selling", "name": "__common__", "print_format_type": "Client", diff --git a/erpnext/selling/Print Format/Sales Order Classic/Sales Order Classic.txt b/erpnext/selling/Print Format/Sales Order Classic/Sales Order Classic.txt index 7f2748ac0c..7ee19c0f2d 100644 --- a/erpnext/selling/Print Format/Sales Order Classic/Sales Order Classic.txt +++ b/erpnext/selling/Print Format/Sales Order Classic/Sales Order Classic.txt @@ -2,14 +2,14 @@ { "creation": "2013-04-19 13:30:51", "docstatus": 0, - "modified": "2013-08-07 19:45:49", + "modified": "2013-12-26 17:35:51", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Sales Order", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n\n", + "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n", "module": "Selling", "name": "__common__", "print_format_type": "Client", diff --git a/erpnext/selling/Print Format/Sales Order Modern/Sales Order Modern.txt b/erpnext/selling/Print Format/Sales Order Modern/Sales Order Modern.txt index e4102b2359..7cf481d7b8 100644 --- a/erpnext/selling/Print Format/Sales Order Modern/Sales Order Modern.txt +++ b/erpnext/selling/Print Format/Sales Order Modern/Sales Order Modern.txt @@ -2,14 +2,14 @@ { "creation": "2013-04-19 13:30:51", "docstatus": 0, - "modified": "2013-08-07 20:12:23", + "modified": "2013-12-26 17:34:24", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Sales Order", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n\n", + "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n", "module": "Selling", "name": "__common__", "print_format_type": "Client", diff --git a/erpnext/selling/Print Format/Sales Order Spartan/Sales Order Spartan.txt b/erpnext/selling/Print Format/Sales Order Spartan/Sales Order Spartan.txt index 105b65b21b..8da27b7d70 100644 --- a/erpnext/selling/Print Format/Sales Order Spartan/Sales Order Spartan.txt +++ b/erpnext/selling/Print Format/Sales Order Spartan/Sales Order Spartan.txt @@ -2,14 +2,14 @@ { "creation": "2013-04-19 13:30:51", "docstatus": 0, - "modified": "2013-08-07 19:45:59", + "modified": "2013-12-26 17:35:29", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Sales Order", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n\n", + "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n", "module": "Selling", "name": "__common__", "print_format_type": "Client", diff --git a/erpnext/selling/doctype/quotation/quotation.txt b/erpnext/selling/doctype/quotation/quotation.txt index 3657e4acef..4795653262 100644 --- a/erpnext/selling/doctype/quotation/quotation.txt +++ b/erpnext/selling/doctype/quotation/quotation.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:08", "docstatus": 0, - "modified": "2013-12-20 19:24:25", + "modified": "2014-01-03 14:54:05", "modified_by": "Administrator", "owner": "Administrator" }, @@ -460,6 +460,13 @@ "print_hide": 1, "read_only": 1 }, + { + "doctype": "DocField", + "fieldname": "discount_amount", + "fieldtype": "Currency", + "label": "Discount Amount", + "options": "Company:company:default_currency" + }, { "doctype": "DocField", "fieldname": "totals", diff --git a/erpnext/selling/doctype/sales_order/sales_order.txt b/erpnext/selling/doctype/sales_order/sales_order.txt index f9582fb213..2dc62f334a 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.txt +++ b/erpnext/selling/doctype/sales_order/sales_order.txt @@ -2,7 +2,7 @@ { "creation": "2013-06-18 12:39:59", "docstatus": 0, - "modified": "2013-12-20 19:24:32", + "modified": "2014-01-03 14:51:19", "modified_by": "Administrator", "owner": "Administrator" }, @@ -480,6 +480,13 @@ "read_only": 1, "width": "150px" }, + { + "doctype": "DocField", + "fieldname": "discount_amount", + "fieldtype": "Currency", + "label": "Discount Amount", + "options": "Company:company:default_currency" + }, { "doctype": "DocField", "fieldname": "totals", diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index 1c8aed3553..330e725ed8 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -225,6 +225,10 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ this.calculate_taxes_and_totals(); }, + + discount_amount: function() { + this.calculate_taxes_and_totals(); + }, commission_rate: function() { this.calculate_commission(); @@ -310,15 +314,17 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ calculate_item_values: function() { var me = this; - $.each(this.frm.item_doclist, function(i, item) { - wn.model.round_floats_in(item); - item.export_amount = flt(item.export_rate * item.qty, precision("export_amount", item)); - - me._set_in_company_currency(item, "ref_rate", "base_ref_rate"); - me._set_in_company_currency(item, "export_rate", "basic_rate"); - me._set_in_company_currency(item, "export_amount", "amount"); - }); + if (!this.discount_amount_applied) { + $.each(this.frm.item_doclist, function(i, item) { + wn.model.round_floats_in(item); + item.export_amount = flt(item.export_rate * item.qty, precision("export_amount", item)); + + me._set_in_company_currency(item, "ref_rate", "base_ref_rate"); + me._set_in_company_currency(item, "export_rate", "basic_rate"); + me._set_in_company_currency(item, "export_amount", "amount"); + }); + } }, determine_exclusive_rate: function() { @@ -341,11 +347,11 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ cumulated_tax_fraction += tax.tax_fraction_for_current_item; }); - if(cumulated_tax_fraction) { + if(cumulated_tax_fraction && !me.discount_amount_applied) { item.amount = flt( (item.export_amount * me.frm.doc.conversion_rate) / (1 + cumulated_tax_fraction), precision("amount", item)); - + item.basic_rate = flt(item.amount / item.qty, precision("basic_rate", item)); if(item.adj_rate == 100) { @@ -385,18 +391,20 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ calculate_net_total: function() { var me = this; - this.frm.doc.net_total = this.frm.doc.net_total_export = 0.0; + $.each(this.frm.item_doclist, function(i, item) { me.frm.doc.net_total += item.amount; me.frm.doc.net_total_export += item.export_amount; }); - + wn.model.round_floats_in(this.frm.doc, ["net_total", "net_total_export"]); }, calculate_totals: function() { + var me = this; var tax_count = this.frm.tax_doclist.length; + this.frm.doc.grand_total = flt( tax_count ? this.frm.tax_doclist[tax_count - 1].total : this.frm.doc.net_total, precision("grand_total")); @@ -405,13 +413,56 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ this.frm.doc.other_charges_total = flt(this.frm.doc.grand_total - this.frm.doc.net_total, precision("other_charges_total")); - this.frm.doc.other_charges_total_export = flt( - this.frm.doc.grand_total_export - this.frm.doc.net_total_export, + this.frm.doc.other_charges_total_export = flt(this.frm.doc.grand_total_export - + this.frm.doc.net_total_export + flt(this.frm.doc.discount_amount), precision("other_charges_total_export")); this.frm.doc.rounded_total = Math.round(this.frm.doc.grand_total); this.frm.doc.rounded_total_export = Math.round(this.frm.doc.grand_total_export); }, + + apply_discount_amount: function() { + var me = this; + var distributed_amount = 0.0; + + if (this.frm.doc.discount_amount) { + var grand_total_for_discount_amount = this.get_grand_total_for_discount_amount(); + // calculate item amount after Discount Amount + if (grand_total_for_discount_amount) { + $.each(this.frm.item_doclist, function(i, item) { + distributed_amount = flt(me.frm.doc.discount_amount) * item.amount / grand_total_for_discount_amount; + item.amount = flt(item.amount - distributed_amount, precision("amount", item)); + }); + + this.discount_amount_applied = true; + this._calculate_taxes_and_totals(); + } + } + }, + + get_grand_total_for_discount_amount: function() { + var me = this; + var total_actual_tax = 0.0; + var actual_taxes_dict = {}; + + $.each(this.frm.tax_doclist, function(i, tax) { + if (tax.charge_type == "Actual") + actual_taxes_dict[tax.idx] = tax.tax_amount; + else if (actual_taxes_dict[tax.row_id] !== null) { + actual_tax_amount = flt(actual_taxes_dict[tax.row_id]) * flt(tax.rate) / 100; + actual_taxes_dict[tax.idx] = actual_tax_amount; + } + }); + + $.each(actual_taxes_dict, function(key, value) { + if (value) + total_actual_tax += value; + }); + + grand_total_for_discount_amount = flt(this.frm.doc.grand_total - total_actual_tax, + precision("grand_total")); + return grand_total_for_discount_amount; + }, calculate_outstanding_amount: function() { // NOTE: diff --git a/erpnext/stock/Print Format/Delivery Note Classic/Delivery Note Classic.txt b/erpnext/stock/Print Format/Delivery Note Classic/Delivery Note Classic.txt index 163dffaa87..d4c0cc1983 100644 --- a/erpnext/stock/Print Format/Delivery Note Classic/Delivery Note Classic.txt +++ b/erpnext/stock/Print Format/Delivery Note Classic/Delivery Note Classic.txt @@ -2,14 +2,14 @@ { "creation": "2013-04-19 13:31:11", "docstatus": 0, - "modified": "2013-08-07 19:44:55", + "modified": "2013-12-26 17:36:51", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Delivery Note", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n\n", + "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n", "module": "Stock", "name": "__common__", "print_format_type": "Client", diff --git a/erpnext/stock/Print Format/Delivery Note Modern/Delivery Note Modern.txt b/erpnext/stock/Print Format/Delivery Note Modern/Delivery Note Modern.txt index f4323a9e1f..3b36f6f1c0 100644 --- a/erpnext/stock/Print Format/Delivery Note Modern/Delivery Note Modern.txt +++ b/erpnext/stock/Print Format/Delivery Note Modern/Delivery Note Modern.txt @@ -2,14 +2,14 @@ { "creation": "2013-04-19 13:31:11", "docstatus": 0, - "modified": "2013-08-07 20:12:29", + "modified": "2013-12-26 17:36:26", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Delivery Note", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n\n", + "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n", "module": "Stock", "name": "__common__", "print_format_type": "Client", diff --git a/erpnext/stock/Print Format/Delivery Note Spartan/Delivery Note Spartan.txt b/erpnext/stock/Print Format/Delivery Note Spartan/Delivery Note Spartan.txt index 03fbef521e..072d411004 100644 --- a/erpnext/stock/Print Format/Delivery Note Spartan/Delivery Note Spartan.txt +++ b/erpnext/stock/Print Format/Delivery Note Spartan/Delivery Note Spartan.txt @@ -2,14 +2,14 @@ { "creation": "2013-04-19 13:31:11", "docstatus": 0, - "modified": "2013-08-07 19:44:37", + "modified": "2013-12-26 17:37:14", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Delivery Note", "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n\n", + "html": "\n\n\n\n\n\n\n\n\n\n\n\n
\n\t\n\t\n
\n", "module": "Stock", "name": "__common__", "print_format_type": "Client", diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.txt b/erpnext/stock/doctype/delivery_note/delivery_note.txt index 36615a28d0..b2677a39e5 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.txt +++ b/erpnext/stock/doctype/delivery_note/delivery_note.txt @@ -2,7 +2,7 @@ { "creation": "2013-05-24 19:29:09", "docstatus": 0, - "modified": "2013-12-20 19:24:02", + "modified": "2014-01-03 14:53:03", "modified_by": "Administrator", "owner": "Administrator" }, @@ -468,7 +468,7 @@ "fieldname": "other_charges_total_export", "fieldtype": "Currency", "label": "Taxes and Charges Total", - "options": "company", + "options": "Company:company:default_currency", "print_hide": 1, "read_only": 1 }, @@ -490,6 +490,13 @@ "read_only": 1, "width": "150px" }, + { + "doctype": "DocField", + "fieldname": "discount_amount", + "fieldtype": "Currency", + "label": "Discount Amount", + "options": "Company:company:default_currency" + }, { "doctype": "DocField", "fieldname": "totals", diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index 1ee5e049e4..23845364da 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -97,7 +97,8 @@ cur_frm.fields_dict['default_sales_cost_center'].get_query = function(doc) { cur_frm.fields_dict['item_tax'].grid.get_field("tax_type").get_query = function(doc, cdt, cdn) { return{ filters:[ - ['Account', 'account_type', 'in', 'Tax, Chargeable'], + ['Account', 'account_type', 'in', + 'Tax, Chargeable, Income Account, Expense Account'], ['Account', 'docstatus', '!=', 2] ] } diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 73e8dc2b09..fb6f73d335 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -151,8 +151,8 @@ class DocType(DocListController, WebsiteGenerator): if d.tax_type: account_type = webnotes.conn.get_value("Account", d.tax_type, "account_type") - if account_type not in ['Tax', 'Chargeable']: - msgprint("'%s' is not Tax / Chargeable Account" % d.tax_type, raise_exception=1) + if account_type not in ['Tax', 'Chargeable', 'Income Account', 'Expense Account']: + msgprint("'%s' is not Tax / Chargeable / Income / Expense Account" % d.tax_type, raise_exception=1) else: if d.tax_type in check_list: msgprint("Rate is entered twice for: '%s'" % d.tax_type, raise_exception=1)