diff --git a/erpnext/accounts/Print Format/POS Invoice/POS Invoice.txt b/erpnext/accounts/Print Format/POS Invoice/POS Invoice.txt index 7f1bba4c961..980195642fb 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": "2014-01-08 19:32:16", + "modified": "2013-12-26 18:13:48", "modified_by": "Administrator", "owner": "Administrator" }, { "doc_type": "Sales Invoice", "doctype": "Print Format", - "html": "\n\t\n\n\t\t\n\t\t\n\n\t\t\n\t\t\n\t\n\n\t\n\t\t\n\t\t
\n\t\t
\n\t\t
\n\t\t
\n\t\t
\n\t\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 fc99597766d..09fcb914766 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 07946f7fcc4..a85a11abc81 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 57c02fe2ec8..e0850e1e9ab 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 ce5350908de..8909d8539e4 100644 --- a/erpnext/accounts/doctype/sales_invoice/pos.js +++ b/erpnext/accounts/doctype/sales_invoice/pos.js @@ -32,12 +32,14 @@ erpnext.POS = Class.extend({ \
\
\ - \ - \ - \ - \ - \ -
Net Total
\ +
\ + \ + \ + \ + \ + \ +
Net Total
\ +
\ \ +
\ + \ + \ + \ + \ + \ + \ +
Discount Amount\ + \ +
\ +
\
\ \ \ @@ -90,6 +104,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("remove-items", function() {me.remove_selected_items();}); this.call_function("make-payment", function() {me.make_payment();}); }, @@ -120,9 +138,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() { @@ -145,23 +163,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() { @@ -184,23 +202,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() { @@ -329,6 +347,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 8e6ecc410f5..1a1fa9f66bb 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() { @@ -146,8 +146,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(); } } }); @@ -335,7 +335,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 decfb425bd8..2259bbefbf6 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -558,12 +558,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 1a5bdf1efc6..33b386ffe37 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.txt +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.txt @@ -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 34ff97ff1c6..02350c5abc3 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 49df5f7291c..8bb154cb7f5 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 0cdead90302..0e9b3db6c07 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 49b914e4a3c..8fab6a9d978 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 ea7a963e4b8..d01627a2083 100644 --- a/erpnext/buying/doctype/purchase_common/purchase_common.js +++ b/erpnext/buying/doctype/purchase_common/purchase_common.js @@ -366,6 +366,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 f2c33fc8413..e151970b06a 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 4b7e79b75d6..ccfff8ad51a 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -132,6 +132,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: @@ -140,7 +146,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}) @@ -156,17 +162,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) @@ -214,11 +222,11 @@ class AccountsController(TransactionBase): "charge_type": tax.charge_type, }) 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,)) @@ -226,14 +234,14 @@ class AccountsController(TransactionBase): # 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 @@ -245,7 +253,10 @@ class AccountsController(TransactionBase): 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 @@ -259,22 +270,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: - tax.total = flt(tax.total, self.precision("total", tax)) - tax.tax_amount = flt(tax.tax_amount, self.precision("tax_amount", tax)) - + 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 @@ -293,9 +318,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 7ba29c20bd4..83b590994d8 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 @@ -166,7 +165,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) @@ -179,7 +178,12 @@ 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"] + # update valuation rate def update_valuation_rate(self, parentfield): """ diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 7447121ee6a..52dcaaaf92b 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,13 +192,42 @@ 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.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/hooks.txt b/erpnext/hooks.txt index 9d4291b2e38..0c8b71a98f4 100644 --- a/erpnext/hooks.txt +++ b/erpnext/hooks.txt @@ -46,13 +46,9 @@ standard_queries = Customer:erpnext.selling.utils.get_customer_list scheduler_event = all:erpnext.support.doctype.support_ticket.get_support_mails.get_support_mails scheduler_event = all:erpnext.hr.doctype.job_applicant.get_job_applications.get_job_applications scheduler_event = all:erpnext.selling.doctype.lead.get_leads.get_leads -scheduler_event = all:webnotes.utils.email_lib.bulk.flush #### Daily -scheduler_event = daily:webnotes.core.doctype.event.event.send_event_digest -scheduler_event = daily:webnotes.core.doctype.notification_count.notification_count.delete_event_notification_count -scheduler_event = daily:webnotes.utils.email_lib.bulk.clear_outbox scheduler_event = daily:erpnext.accounts.doctype.sales_invoice.sales_invoice.manage_recurring_invoices scheduler_event = daily:erpnext.setup.doctype.backup_manager.backup_manager.take_backups_daily scheduler_event = daily:erpnext.stock.utils.reorder_item diff --git a/erpnext/patches.txt b/erpnext/patches.txt index c1ab0982988..f39e2142456 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 7c4ac332b08..789954b8988 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", @@ -265,4 +265,9 @@ patch_list = [ "patches.1401.p01_move_related_property_setters_to_custom_field", "patches.1401.p01_make_buying_selling_as_check_box_in_price_list", "patches.1401.update_billing_status_for_zero_value_order", + "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 ad73d77616c..0dfdd07376a 100644 --- a/erpnext/public/js/transaction.js +++ b/erpnext/public/js/transaction.js @@ -508,10 +508,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(); @@ -519,18 +526,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); @@ -541,23 +553,21 @@ 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); - // Adjust divisional loss to the last item if (tax.charge_type == "Actual") { actual_tax_dict[tax.idx] -= current_tax_amount; @@ -566,13 +576,15 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ } } - // 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) { @@ -597,14 +609,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) { - tax.total = flt(tax.total, precision("total", tax)); - tax.tax_amount = flt(tax.tax_amount, precision("tax_amount", tax)); + 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); @@ -627,9 +657,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 e7588c4522f..05c3c598cab 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 20d380dcbff..35850e62ebd 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 c5b4cb92b3b..3b4452666be 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 7f2748ac0c4..7ee19c0f2de 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 e4102b23597..7cf481d7b87 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 105b65b21b1..8da27b7d70b 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 3657e4acefc..47956532623 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 f9582fb213e..2dc62f334a3 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 d8afec5cd03..1baaf7b4d57 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 163dffaa871..d4c0cc19831 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 f4323a9e1fd..3b36f6f1c0b 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 03fbef521ec..072d411004f 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 36615a28d08..b2677a39e58 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 5fca4f455ea..e894d0db889 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -94,7 +94,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 73e8dc2b098..fb6f73d3355 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)