[calculations] [client/server] first cut
diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.js b/accounts/doctype/purchase_invoice/purchase_invoice.js
index b498ce2..3ddf907 100644
--- a/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -34,67 +34,12 @@
 		
 		cur_frm.cscript.is_opening(doc);
 	},
-	onload_post_render: function(doc, dt, dn) {	
-		var me = this;	
-		var callback1 = function(doc, dt, dn) {
-			var callback2 = function(doc, dt, dn) {
-				if(doc.__islocal && doc.supplier) cur_frm.cscript.supplier(doc, dt, dn);			
-			}
-			me.update_item_details(doc, dt, dn, callback2);
-		}
-		
-		// TODO: improve this
-		if(this.frm.doc.__islocal) {
-			if (this.frm.fields_dict.price_list_name && this.frm.doc.price_list_name) {
-				this.price_list_name(callback1);
-			} else {
-				callback1(doc, dt, dn);
-			}
-		}
-	}
 });
 
 // for backward compatibility: combine new and previous states
 $.extend(cur_frm.cscript, new erpnext.buying.PurchaseInvoiceController({frm: cur_frm}));
 
 
-cur_frm.cscript.onload = function(doc,dt,dn) {
-	if(!doc.posting_date) set_multiple(dt,dn,{posting_date:get_today()});
-}
-
-cur_frm.cscript.supplier = function(doc,dt,dn) {
-	var callback = function(r,rt) {
-			var doc = locals[cur_frm.doctype][cur_frm.docname];		
-			get_server_fields('get_credit_to','','',doc, dt, dn, 0, callback2);
-	}
-	
-	var callback2 = function(r,rt){
-		var doc = locals[cur_frm.doctype][cur_frm.docname];
-		var el = getchildren('Purchase Invoice Item',doc.name,'entries');
-		for(var i in el){
-			if(el[i].item_code && (!el[i].expense_head || !el[i].cost_center)){
-				args = {
-					item_code: el[i].item_code,
-					expense_head: el[i].expense_head,
-					cost_center: el[i].cost_center
-				};
-				get_server_fields('get_default_values', JSON.stringify(args), 'entries', doc, el[i].doctype, el[i].name, 1);
-			}
-		}
-		cur_frm.cscript.calc_amount(doc, 1);
-	}
-
-	if (doc.supplier) {
-		get_server_fields('get_default_supplier_address',
-			JSON.stringify({ supplier: doc.supplier }),'', doc, dt, dn, 1, function(doc, dt, dn) {
-				cur_frm.refresh();
-				callback(doc, dt, dn);
-			});
-		unhide_field(['supplier_address','contact_person']);
-	}
-
-}
-
 cur_frm.cscript.supplier_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {
 	if(doc.supplier) get_server_fields('get_supplier_address', JSON.stringify({supplier: doc.supplier, address: doc.supplier_address, contact: doc.contact_person}),'', doc, dt, dn, 1);
 }
diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py
index b63a176..7f8ad63 100644
--- a/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -91,6 +91,11 @@
 			msgprint("%s does not have an Account Head in %s. You must first create it from the Supplier Master" % (self.doc.supplier, self.doc.company))
 		return ret
 		
+	def set_supplier_defaults(self):
+		# TODO cleanup these methods
+		self.doc.fields.update(self.get_credit_to())
+		super(DocType, self).set_supplier_defaults()
+		
 	def get_cust(self):
 		ret = {}
 		if self.doc.credit_to:
@@ -100,31 +105,6 @@
 			
 		return ret
 		
-	def get_default_values(self, args):
-		if isinstance(args, basestring):
-			import json
-			args = json.loads(args)
-		
-		out = webnotes._dict()
-		
-		item = webnotes.conn.sql("""select name, purchase_account, cost_center,
-			is_stock_item from `tabItem` where name=%s""", args.get("item_code"), as_dict=1)
-		
-		if item and item[0]:
-			item = item[0]
-			
-			if cint(webnotes.defaults.get_global_default("auto_inventory_accounting")) and \
-				item.is_stock_item == "Yes":
-					# unset expense head for stock item and auto inventory accounting
-					out.expense_head = out.cost_center = None
-			else:
-				if not args.get("expense_head"):
-					out.expense_head = item.purchase_account
-				if not args.get("cost_center"):
-					out.cost_center = item.cost_center
-		
-		return out
-			
 	def pull_details(self):
 		if self.doc.purchase_receipt_main:
 			self.validate_duplicate_docname('purchase_receipt')
diff --git a/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index a70c932..ebd44d4 100644
--- a/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -119,25 +119,6 @@
 		wrapper.insert()
 		wrapper.load_from_db()
 		
-		self.assertEqual(wrapper.doclist[0].net_total, 1250)
-		
-		# tax amounts
-		expected_values = [
-			["_Test Account Shipping Charges - _TC", 100, 1350],
-			["_Test Account Customs Duty - _TC", 125, 1350],
-			["_Test Account Excise Duty - _TC", 140, 1490],
-			["_Test Account Education Cess - _TC", 2.8, 1492.8],
-			["_Test Account S&H Education Cess - _TC", 1.4, 1494.2],
-			["_Test Account CST - _TC", 29.88, 1524.08],
-			["_Test Account VAT - _TC", 156.25, 1680.33],
-			["_Test Account Discount - _TC", 168.03, 1512.30],
-		]
-		
-		for i, tax in enumerate(wrapper.doclist.get({"parentfield": "purchase_tax_details"})):
-			self.assertEqual(tax.account_head, expected_values[i][0])
-			self.assertEqual(tax.tax_amount, expected_values[i][1])
-			self.assertEqual(tax.total, expected_values[i][2])
-
 		expected_values = [
 			["_Test Item Home Desktop 100", 90, 59],
 			["_Test Item Home Desktop 200", 135, 177]
@@ -147,13 +128,41 @@
 			self.assertEqual(item.item_tax_amount, expected_values[i][1])
 			self.assertEqual(item.valuation_rate, expected_values[i][2])
 			
+		self.assertEqual(wrapper.doclist[0].net_total, 1250)
+		
+		# tax amounts
+		expected_values = [
+			["_Test Account Shipping Charges - _TC", 100, 1350],
+			["_Test Account Customs Duty - _TC", 125, 1350],
+			["_Test Account Excise Duty - _TC", 140, 1490],
+			["_Test Account Education Cess - _TC", 2.8, 1492.8],
+			["_Test Account S&H Education Cess - _TC", 1.4, 1494.2],
+			["_Test Account CST - _TC", 29.88, 1524.08],
+			["_Test Account VAT - _TC", 156.25, 1680.33],
+			["_Test Account Discount - _TC", 168.03, 1512.30],
+		]
+		
+		for i, tax in enumerate(wrapper.doclist.get({"parentfield": "purchase_tax_details"})):
+			self.assertEqual(tax.account_head, expected_values[i][0])
+			self.assertEqual(tax.tax_amount, expected_values[i][1])
+			self.assertEqual(tax.total, expected_values[i][2])
+			
 	def test_purchase_invoice_with_subcontracted_item(self):
 		wrapper = webnotes.bean(copy=test_records[0])
 		wrapper.doclist[1].item_code = "_Test FG Item"
 		wrapper.run_method("calculate_taxes_and_totals")
 		wrapper.insert()
 		wrapper.load_from_db()
-
+		
+		expected_values = [
+			["_Test FG Item", 90, 7059],
+			["_Test Item Home Desktop 200", 135, 177]
+		]
+		for i, item in enumerate(wrapper.doclist.get({"parentfield": "entries"})):
+			self.assertEqual(item.item_code, expected_values[i][0])
+			self.assertEqual(item.item_tax_amount, expected_values[i][1])
+			self.assertEqual(item.valuation_rate, expected_values[i][2])
+		
 		self.assertEqual(wrapper.doclist[0].net_total, 1250)
 
 		# tax amounts
@@ -172,15 +181,6 @@
 			self.assertEqual(tax.account_head, expected_values[i][0])
 			self.assertEqual(tax.tax_amount, expected_values[i][1])
 			self.assertEqual(tax.total, expected_values[i][2])
-
-		expected_values = [
-			["_Test FG Item", 90, 7059],
-			["_Test Item Home Desktop 200", 135, 177]
-		]
-		for i, item in enumerate(wrapper.doclist.get({"parentfield": "entries"})):
-			self.assertEqual(item.item_code, expected_values[i][0])
-			self.assertEqual(item.item_tax_amount, expected_values[i][1])
-			self.assertEqual(item.valuation_rate, expected_values[i][2])
 			
 	def test_purchase_invoice_with_advance(self):
 		from accounts.doctype.journal_voucher.test_journal_voucher \
diff --git a/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py
index 505848a..7c4b8b1 100644
--- a/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -110,8 +110,8 @@
 		for i, tax in enumerate(si.doclist.get({"parentfield": "other_charges"})):
 			tax.idx = i+1
 		
-		si.doclist[1].export_rate = 62.5
-		si.doclist[1].export_rate = 191
+		si.doclist[1].ref_rate = 62.5
+		si.doclist[1].ref_rate = 191
 		for i in [3, 5, 6, 7, 8, 9]:
 			si.doclist[i].included_in_print_rate = 1
 		
@@ -173,9 +173,9 @@
 		si = webnotes.bean(copy=test_records[3])
 		si.doc.currency = "USD"
 		si.doc.conversion_rate = 50
-		si.doclist[1].export_rate = 50
+		si.doclist[1].ref_rate = 55.56
 		si.doclist[1].adj_rate = 10
-		si.doclist[2].export_rate = 150
+		si.doclist[2].ref_rate = 187.5
 		si.doclist[2].adj_rate = 20
 		si.doclist[9].rate = 5000
 		
@@ -317,7 +317,7 @@
 		pos[0]["cash_bank_account"] = "_Test Account Bank Account - _TC"
 		pos[0]["paid_amount"] = 600.0
 
-		si = webnotes.bean(pos)
+		si = webnotes.bean(copy=pos)
 		si.insert()
 		si.submit()
 		
@@ -340,11 +340,11 @@
 		
 		expected_gl_entries = sorted([
 			[si.doc.debit_to, 630.0, 0.0],
-			[test_records[1][1]["income_account"], 0.0, 500.0],
-			[test_records[1][2]["account_head"], 0.0, 80.0],
-			[test_records[1][3]["account_head"], 0.0, 50.0],
+			[pos[1]["income_account"], 0.0, 500.0],
+			[pos[2]["account_head"], 0.0, 80.0],
+			[pos[3]["account_head"], 0.0, 50.0],
 			[stock_in_hand_account, 0.0, 375.0],
-			[test_records[1][1]["expense_account"], 375.0, 0.0],
+			[pos[1]["expense_account"], 375.0, 0.0],
 			[si.doc.debit_to, 0.0, 600.0],
 			["_Test Account Bank Account - _TC", 600.0, 0.0]
 		])
@@ -760,6 +760,7 @@
 			"item_code": "_Test Item Home Desktop 100",
 			"item_name": "_Test Item Home Desktop 100",
 			"qty": 10,
+			"ref_rate": 50,
 			"export_rate": 50,
 			"stock_uom": "_Test UOM",
 			"item_tax_rate": json.dumps({"_Test Account Excise Duty - _TC": 10}),
@@ -773,6 +774,7 @@
 			"item_code": "_Test Item Home Desktop 200",
 			"item_name": "_Test Item Home Desktop 200",
 			"qty": 5,
+			"ref_rate": 150,
 			"export_rate": 150,
 			"stock_uom": "_Test UOM",
 			"income_account": "Sales - _TC",
@@ -883,6 +885,7 @@
 			"item_code": "_Test Item Home Desktop 100",
 			"item_name": "_Test Item Home Desktop 100",
 			"qty": 10,
+			"ref_rate": 62.5,
 			"export_rate": 62.5,
 			"stock_uom": "_Test UOM",
 			"item_tax_rate": json.dumps({"_Test Account Excise Duty - _TC": 10}),
@@ -896,6 +899,7 @@
 			"item_code": "_Test Item Home Desktop 200",
 			"item_name": "_Test Item Home Desktop 200",
 			"qty": 5,
+			"ref_rate": 190.66,
 			"export_rate": 190.66,
 			"stock_uom": "_Test UOM",
 			"income_account": "Sales - _TC",
diff --git a/buying/doctype/purchase_common/purchase_common.js b/buying/doctype/purchase_common/purchase_common.js
index b1ab40b..3202122 100644
--- a/buying/doctype/purchase_common/purchase_common.js
+++ b/buying/doctype/purchase_common/purchase_common.js
@@ -20,8 +20,9 @@
 // cur_frm.cscript.fname - Details fieldname
 
 wn.provide("erpnext.buying");
+wn.require("app/js/transaction.js");
 
-erpnext.buying.BuyingController = wn.ui.form.Controller.extend({
+erpnext.buying.BuyingController = erpnext.TransactionController.extend({
 	setup: function() {
 		var me = this;
 		
@@ -42,50 +43,39 @@
 		}
 	},
 	
-	refresh: function() {
-		this.frm.clear_custom_buttons();
-		erpnext.hide_naming_series();
+	validate: function() {
 		
-		if(this.frm.fields_dict.supplier)
-			this.frm.toggle_display("contact_section", this.frm.doc.supplier);
-		
-		if(this.frm.fields_dict.currency)
-			this.set_dynamic_labels();
 	},
 	
-	price_list_name: function(callback_fn) {
-		var me = this;
-		
-		if(this.frm.doc.price_list_name) {
-			if(!this.frm.doc.price_list_currency) {
-				// set price list currency
+	supplier: function() {
+		if(this.frm.doc.supplier || this.frm.doc.credit_to) {
+			if(!this.frm.doc.company) {
+				this.frm.set_value("supplier", null);
+				msgprint(wn._("Please specify Company"));
+			} else {
+				var me = this;
+				var price_list_name = this.frm.doc.price_list_name;
+
 				this.frm.call({
-					method: "setup.utils.get_price_list_currency",
-					args: {args: {
-						price_list_name: this.frm.doc.price_list_name,
-						use_for: "buying"
-					}},
+					doc: this.frm.doc,
+					method: "set_supplier_defaults",
+					freeze: true,
 					callback: function(r) {
 						if(!r.exc) {
-							me.price_list_currency();
-							if (typeof callback_fn === "function") 
-								callback_fn(me.frm.doc, me.frm.doc.doctype, me.frm.doc.name);
+							me.frm.refresh_fields();
+							if(me.frm.doc.price_list_name !== price_list_name) me.price_list_name();
 						}
 					}
 				});
-			} else {
-				me.price_list_currency();
-				if (typeof callback_fn === "function") 
-					callback_fn(me.frm.doc, me.frm.doc.doctype, me.frm.doc.name);
 			}
-		} 
-	},
+		}
+	}
 	
 	item_code: function(doc, cdt, cdn) {
 		var me = this;
 		var item = wn.model.get_doc(cdt, cdn);
 		if(item.item_code) {
-			if(!this.validate_company_and_party()) {
+			if(!this.validate_company_and_party("supplier")) {
 				item.item_code = null;
 				refresh_field("item_code", item.name, item.parentfield);
 			} else {
@@ -109,65 +99,115 @@
 						}
 					},
 					callback: function(r) {
-						// TODO: calculate
+						if(!r.exc) {
+							me.ref_rate(me.frm.doc, cdt, cdn);
+						}
 					}
 				});
 			}
 		}
 	},
 	
-	validate_company_and_party: function() {
-		var valid = true;
-		$.each(["company", "supplier"], function(i, fieldname) {
-			if(!me.frm.doc[fieldname]) {
-				valid = false;
-				msgprint(wn._("Please specify") + ": " + 
-					wn.meta.get_label(me.frm.doc.doctype, fieldname, me.frm.doc.name) + 
-					". " + wn._("It is needed to fetch Item Details."));
-			}
-		});
-		return valid;
+	price_list_name: function(callback_fn) {
+		this._super("buying");
 	},
 	
-	update_item_details: function(doc, dt, dn, callback) {
-		if(!this.frm.doc.__islocal) return;
-		
+	calculate_taxes_and_totals: function() {
+		this._super();
+		this.calculate_outstanding_amount();
+		this.frm.refresh_fields();
+	},
+	
+	calculate_item_values: function() {
 		var me = this;
-		var children = getchildren(this.tname, this.frm.doc.name, this.fname);
-		if(children && children.length) {
-			this.frm.call({
-				doc: me.frm.doc,
-				method: "update_item_details",
-				callback: function(r) {
-					if(!r.exc) {
-						refresh_field(me.fname);
-						me.load_defaults(me.frm.doc, dt, dn, callback);
-					}
-				}
-			})
-		} else {
-			this.load_taxes(doc, dt, dn, callback);
+		
+		if(this.frm.doc.doctype != "Purchase Invoice") {
+			wn.meta.docfield_map[this.tname]["rate"] = $.extend({}, 
+				wn.meta.docfield_map[this.tname]["purchase_rate"]);
+		}
+		
+		$.each(this.frm.item_doclist, function(i, item) {
+			if(me.frm.doc.doctype != "Purchase Invoice") {
+				item.rate = item.purchase_rate;
+			}
+			
+			wn.model.round_floats_in(item);
+			item.import_amount = flt(item.import_rate * item.qty, precision("import_amount", item));
+			item.item_tax_amount = 0.0;
+			
+			me._set_in_company_currency(item, "import_ref_rate", "purchase_ref_rate");
+			me._set_in_company_currency(item, "import_rate", "rate");
+			me._set_in_company_currency(item, "import_amount", "amount");
+		});
+	},
+	
+	calculate_net_total: function() {
+		var me = this;
+
+		this.frm.doc.net_total = this.frm.doc.net_total_import = 0.0;
+		$.each(this.frm.item_doclist, function(i, item) {
+			me.frm.doc.net_total += item.amount;
+			me.frm.doc.net_total_import += item.import_amount;
+		});
+		
+		wn.model.round_floats_in(this.frm.doc, ["net_total", "net_total_import"]);
+	},
+	
+	calculate_totals: function() {
+		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"));
+		this.frm.doc.grand_total_import = flt(this.frm.doc.grand_total / this.frm.doc.conversion_rate,
+			precision("grand_total_import"));
+			
+		this.frm.doc.total_tax = flt(this.frm.doc.grand_total - this.frm.doc.net_total,
+			precision("total_tax"));
+		
+		if(wn.meta.get_docfield(this.frm.doc.doctype, "rounded_total", this.frm.doc.name)) {
+			this.frm.doc.rounded_total = Math.round(this.frm.doc.grand_total);
+		}
+		
+		if(wn.meta.get_docfield(this.frm.doc.doctype, "rounded_total_import", this.frm.doc.name)) {
+			this.frm.doc.rounded_total_import = Math.round(this.frm.doc.grand_total_import);
 		}
 	},
 	
-	currency: function() {
-		this.price_list_currency();
+	_cleanup: function() {
+		this._super();
+		this.frm.doc.in_words = this.frm.doc.in_words_import = "";
+
+		// except in purchase invoice, rate field is purchase_rate		
+		// reset fieldname of rate
+		if(this.frm.doc.doctype != "Purchase Invoice") {
+			delete wn.meta.docfield_map[this.tname]["rate"];
+			
+			$.each(this.frm.item_doclist, function(i, item) {
+				item.purchase_rate = item.rate;
+				delete item["rate"];
+			});
+		}
 	},
 	
-	company: function() {
-		this.set_dynamic_labels();
+	calculate_outstanding_amount: function() {
+		if(this.frm.doc.doctype == "Purchase Invoice" && this.frm.doc.docstatus < 2) {
+			wn.model.round_floats_in(this.frm.doc, ["total_advance", "write_off_amount"]);
+			this.frm.doc.total_amount_to_pay = flt(this.frm.doc.grand_total - this.frm.doc.write_off_amount,
+				precision("total_amount_to_pay"));
+			this.frm.doc.outstanding_amount = flt(this.frm.doc.total_amount_to_pay - this.frm.doc.total_advance,
+				precision("outstanding_amount"));
+		}
 	},
 	
-	price_list_currency: function() {
-		this.frm.toggle_reqd("plc_conversion_rate",
-			!!(this.frm.doc.price_list_name && this.frm.doc.price_list_currency));
-		
-		this.set_dynamic_labels();
-				
-		if(this.frm.doc.price_list_currency === this.get_company_currency())
-			this.frm.set_value("plc_conversion_rate", 1.0);
-		else if(this.frm.doc.price_list_currency === this.frm.doc.currency)
-			this.frm.set_value("plc_conversion_rate", this.frm.doc.conversion_rate || 1.0);		
+	set_item_tax_amount: function(item, tax, current_tax_amount) {
+		// item_tax_amount is the total tax amount applied on that item
+		// stored for valuation 
+		// 
+		// TODO: rename item_tax_amount to valuation_tax_amount
+		if(["Valuation", "Valuation and Total"].indexOf(tax.category) != -1) {
+			// accumulate only if tax is for Valuation / Valuation and Total
+			item.item_tax_amount += flt(current_tax_amount, precision("item_tax_amount", item));
+		}
 	},
 	
 	set_dynamic_labels: function(doc, dt, dn) {
@@ -265,10 +305,6 @@
 			$wrapper.find('[data-grid-fieldname="'+fname+'"]').text(label);
 		});
 	},
-	
-	get_company_currency: function() {
-		return erpnext.get_currency(this.frm.doc.company);
-	}
 });
 
 // to save previous state of cur_frm.cscript
@@ -284,54 +320,6 @@
 var tname = cur_frm.cscript.tname;
 var fname = cur_frm.cscript.fname;
 
-cur_frm.cscript.get_default_schedule_date = function(doc) {
-		var ch = getchildren( tname, doc.name, fname);
-		if (flt(ch.length) > 0){
-			$c_obj(make_doclist(doc.doctype, doc.name), 'get_default_schedule_date', '', function(r, rt) { refresh_field(fname); });
-		}
-}
-
-cur_frm.cscript.load_taxes = function(doc, cdt, cdn, callback) {
-	// run if this is not executed from dt_map...
-	doc = locals[doc.doctype][doc.name];
-	if(doc.supplier || getchildren('Purchase Taxes and Charges', doc.name, 'purchase_tax_details', doc.doctype).length) {
-		if(callback) {
-			callback(doc, cdt, cdn);
-		}
-	} else {
-		$c_obj(make_doclist(doc.doctype, doc.name),'load_default_taxes','',function(r,rt){
-			refresh_field('purchase_tax_details');
-			if(callback) callback(doc, cdt, cdn);
-		});
-	}
-}
-
-
-
-// Gets called after existing item details are update to fill in
-// remaining default values
-cur_frm.cscript.load_defaults = function(doc, dt, dn, callback) {
-	if(!cur_frm.doc.__islocal) { return; }
-
-	doc = locals[doc.doctype][doc.name];
-	var fields_to_refresh = wn.model.set_default_values(doc);
-	if(fields_to_refresh) { refresh_many(fields_to_refresh); }
-
-	fields_to_refresh = null;
-	var children = getchildren(cur_frm.cscript.tname, doc.name, cur_frm.cscript.fname);
-	if(!children) { return; }
-	for(var i=0; i<children.length; i++) {
-		wn.model.set_default_values(children[i]);
-	}
-	refresh_field(cur_frm.cscript.fname);
-	cur_frm.cscript.load_taxes(doc, dt, dn, callback);
-}
-
-// ======================== Conversion Rate ==========================================
-cur_frm.cscript.conversion_rate = function(doc,cdt,cdn) {
-	cur_frm.cscript.calc_amount( doc, 1);
-}
-
 //==================== Item Code Get Query =======================================================
 // Only Is Purchase Item = 'Yes' and Items not moved to trash are allowed.
 cur_frm.fields_dict[fname].grid.get_field("item_code").get_query = function(doc, cdt, cdn) {
diff --git a/buying/doctype/purchase_common/purchase_common.py b/buying/doctype/purchase_common/purchase_common.py
index d5b563b..7945954 100644
--- a/buying/doctype/purchase_common/purchase_common.py
+++ b/buying/doctype/purchase_common/purchase_common.py
@@ -69,17 +69,6 @@
 			msgprint(_("Hey there! You need to put at least one item in \
 				the item table."), raise_exception=True)
 
-
-	def get_default_schedule_date( self, obj):
-		for d in getlist( obj.doclist, obj.fname):
-			item = sql("select lead_time_days from `tabItem` where name = '%s' and (ifnull(end_of_life,'')='' or end_of_life = '0000-00-00' or end_of_life >	now())" % cstr(d.item_code) , as_dict = 1)
-			ltd = item and cint(item[0]['lead_time_days']) or 0
-			if ltd and obj.doc.transaction_date:
-				if d.fields.has_key('lead_time_date') or obj.doc.doctype == 'Material Request':
-					d.lead_time_date = cstr(add_days( obj.doc.transaction_date, cint(ltd)))
-				if not d.fields.has_key('prevdoc_docname') or (d.fields.has_key('prevdoc_docname') and not d.prevdoc_docname):
-					d.schedule_date =	cstr( add_days( obj.doc.transaction_date, cint(ltd)))
-				
 	# Client Trigger functions
 	#------------------------------------------------------------------------------------------------
 
diff --git a/buying/doctype/purchase_order/purchase_order.js b/buying/doctype/purchase_order/purchase_order.js
index afe4741..ad2db91 100644
--- a/buying/doctype/purchase_order/purchase_order.js
+++ b/buying/doctype/purchase_order/purchase_order.js
@@ -39,26 +39,6 @@
 			cur_frm.add_custom_button('Unstop Purchase Order', cur_frm.cscript['Unstop Purchase Order']);
 			
 	},
-	
-	onload_post_render: function(doc, dt, dn) {	
-		var me = this;	
-		var callback1 = function(doc, dt, dn) {
-			var callback2 = function(doc, dt, dn) {
-				if(doc.__islocal) cur_frm.cscript.get_default_schedule_date(doc);				
-			}
-			me.update_item_details(doc, dt, dn, callback2);
-		}
-		
-		// TODO: improve this
-		if(this.frm.doc.__islocal) {
-			if (this.frm.fields_dict.price_list_name && this.frm.doc.price_list_name) {
-				this.price_list_name(callback1);
-			} else {
-				callback1(doc, dt, dn);
-			}
-		}
-	}
-	
 });
 
 var new_cscript = new erpnext.buying.PurchaseOrderController({frm: cur_frm});
@@ -66,28 +46,6 @@
 // for backward compatibility: combine new and previous states
 $.extend(cur_frm.cscript, new_cscript);
 
-cur_frm.cscript.onload = function(doc, cdt, cdn) {	
-	// set missing values in parent doc
-	set_missing_values(doc, {
-		fiscal_year: sys_defaults.fiscal_year,
-		conversion_rate: 1,
-		currency: sys_defaults.currency,
-		status: "Draft",
-		transaction_date: get_today(),
-		is_subcontracted: "No"
-	});
-}
-
-cur_frm.cscript.supplier = function(doc,dt,dn) {
-	if (doc.supplier) {
-		get_server_fields('get_default_supplier_address',
-			JSON.stringify({ supplier: doc.supplier }),'', doc, dt, dn, 1, function() {
-				cur_frm.refresh();
-			});
-		$(cur_frm.fields_dict.contact_section.row.wrapper).toggle(true);
-	}
-}
-
 cur_frm.cscript.supplier_address = cur_frm.cscript.contact_person = function(doc,dt,dn) {		
 	if(doc.supplier) get_server_fields('get_supplier_address', JSON.stringify({supplier: doc.supplier, address: doc.supplier_address, contact: doc.contact_person}),'', doc, dt, dn, 1);
 }
@@ -111,10 +69,6 @@
 	locals['Contact'][dn].supplier_name = locals[cur_frm.doctype][cur_frm.docname].supplier_name;
 }
 
-cur_frm.cscript.transaction_date = function(doc,cdt,cdn){
-	if(doc.__islocal){ cur_frm.cscript.get_default_schedule_date(doc); }
-}
-
 cur_frm.fields_dict['po_details'].grid.get_field('project_name').get_query = function(doc, cdt, cdn) {
 	return 'SELECT `tabProject`.name FROM `tabProject` \
 		WHERE `tabProject`.status not in ("Completed", "Cancelled") \
diff --git a/buying/doctype/purchase_order/purchase_order.py b/buying/doctype/purchase_order/purchase_order.py
index 218d4bf..bf59389 100644
--- a/buying/doctype/purchase_order/purchase_order.py
+++ b/buying/doctype/purchase_order/purchase_order.py
@@ -65,10 +65,6 @@
 		self.validate_for_subcontracting()
 		self.update_raw_materials_supplied("po_raw_material_details")
 		
-
-	def get_default_schedule_date(self):
-		get_obj(dt = 'Purchase Common').get_default_schedule_date(self)
-		
 	def validate_fiscal_year(self):
 		get_obj(dt = 'Purchase Common').validate_fiscal_year(self.doc.fiscal_year,self.doc.transaction_date,'PO Date')
 
@@ -101,7 +97,6 @@
 				"""[['Supplier Quotation', 'Purchase Order'],
 				['Supplier Quotation Item', 'Purchase Order Item'],
 				['Purchase Taxes and Charges', 'Purchase Taxes and Charges']]""")
-			self.get_default_schedule_date()
 			for d in getlist(self.doclist, 'po_details'):
 				if d.prevdoc_detail_docname and not d.schedule_date:
 					d.schedule_date = webnotes.conn.get_value("Material Request Item",
diff --git a/buying/doctype/supplier_quotation/supplier_quotation.js b/buying/doctype/supplier_quotation/supplier_quotation.js
index 1e4f6cb..4e5b62b 100644
--- a/buying/doctype/supplier_quotation/supplier_quotation.js
+++ b/buying/doctype/supplier_quotation/supplier_quotation.js
@@ -26,29 +26,11 @@
 erpnext.buying.SupplierQuotationController = erpnext.buying.BuyingController.extend({
 	refresh: function() {
 		this._super();
-		
 
 		if (this.frm.doc.docstatus === 1) {
 			cur_frm.add_custom_button("Make Purchase Order", cur_frm.cscript.make_purchase_order);
 		}
-	},
-	
-	onload_post_render: function(doc, dt, dn) {	
-		var me = this;
-		var callback = function(doc, dt, dn) {
-			cur_frm.cscript.load_taxes(me.frm.doc);
-		}
-		
-		// TODO: improve this
-		if(this.frm.doc.__islocal) {
-			if (this.frm.fields_dict.price_list_name && this.frm.doc.price_list_name) {
-				this.price_list_name(callback);
-			} else {
-				callback(doc, dt, dn);
-			}
-		}
-	}
-	
+	},	
 });
 
 var new_cscript = new erpnext.buying.SupplierQuotationController({frm: cur_frm});
@@ -56,19 +38,6 @@
 // for backward compatibility: combine new and previous states
 $.extend(cur_frm.cscript, new_cscript);
 
-
-cur_frm.cscript.onload = function(doc, dt, dn) {
-	// set missing values in parent doc
-	set_missing_values(doc, {
-		fiscal_year: sys_defaults.fiscal_year,
-		conversion_rate: 1,
-		currency: sys_defaults.currency,
-		status: "Draft",
-		transaction_date: get_today(),
-		is_subcontracted: "No"
-	});
-}
-
 cur_frm.cscript.make_purchase_order = function() {
 	var new_po_name = wn.model.make_new_doc_and_get_name("Purchase Order");
 	$c("dt_map", {
diff --git a/buying/utils.py b/buying/utils.py
index 952d70a..2c29e2c 100644
--- a/buying/utils.py
+++ b/buying/utils.py
@@ -65,7 +65,10 @@
 		out.purchase_ref_rate = out.discount_rate = out.purchase_rate = \
 			out.import_ref_rate = out.import_rate = 0.0
 		out.update(_get_price_list_rate(args, item_bean, meta))
-			
+	
+	if args.doctype == "Material Request":
+		out.min_order_qty = flt(item.min_order_qty)
+	
 	return out
 	
 def _get_basic_details(args, item_bean):
diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py
index 19b2a50..1499e0a 100644
--- a/controllers/accounts_controller.py
+++ b/controllers/accounts_controller.py
@@ -16,14 +16,254 @@
 
 from __future__ import unicode_literals
 import webnotes
-from webnotes.utils import flt
-
-from utilities.transaction_base import TransactionBase
+from webnotes import _, msgprint
+from webnotes.utils import flt, cint
+from setup.utils import get_company_currency, get_price_list_currency
+from utilities.transaction_base import TransactionBase, validate_conversion_rate
+import json
 
 class AccountsController(TransactionBase):
 	def validate(self):
-		if self.meta.get_field("grand_total"):
+		self.set_missing_values(for_validate=True)
+		
+		if self.meta.get_field("currency"):
+			self.company_currency = get_company_currency(self.doc.company)
+			
+			validate_conversion_rate(self.doc.currency, self.doc.conversion_rate,
+				self.meta.get_label("conversion_rate"), self.doc.company)
+			
+			# self.calculate_taxes_and_totals()
 			self.validate_value("grand_total", ">=", 0)
+			self.set_total_in_words()
+			
+	def set_price_list_currency(self, buying_or_selling):
+		# TODO - change this, since price list now has only one currency allowed
+		if self.meta.get_field("price_list_name") and self.doc.price_list_name and \
+			not self.doc.price_list_currency:
+				self.doc.fields.update(get_price_list_currency({
+					"price_list_name": self.doc.price_list_name, 
+					"use_for": buying_or_selling
+				}))
+				
+	def set_missing_item_details(self, get_item_details):
+		"""set missing item values"""
+		for item in self.doclist.get({"parentfield": self.fname}):
+			if item.fields.get("item_code"):
+				args = item.fields.copy().update(self.doc.fields)
+				ret = get_item_details(args)
+				for fieldname, value in ret.items():
+					if self.meta.get_field(fieldname, parentfield=self.fname) and \
+						not item.fields.get(fieldname):
+							item.fields[fieldname] = value
+							
+	def set_taxes(self, tax_doctype, tax_parentfield, tax_master_field):
+		if not self.meta.get_field(tax_parentfield):
+			return
+			
+		if not self.doclist.get({"parentfield": tax_parentfield}):
+			if not self.doc.fields.get(tax_master_field):
+				# get the default tax master
+				self.doc.fields[tax_master_field] = \
+					webnotes.conn.get_value(tax_doctype + " Master", {"is_default": 1})
+				
+			if self.doc.fields.get(tax_master_field):
+				from webnotes.model import default_fields
+				tax_master = webnotes.bean(tax_doctype, self.doc.fields.get(tax_master_field))
+				
+				for i, tax in enumerate(tax_master.doclist.get({"parentfield": tax_parentfield})):
+					for fieldname in default_fields:
+						tax.fields[fieldname] = None
+					
+					tax.fields.update({
+						"doctype": tax_doctype,
+						"parentfield": tax_parentfield,
+						"idx": i+1
+					})
+					
+					self.doclist.append(tax)
+					
+	def calculate_taxes_and_totals(self):
+		self.doc.conversion_rate = flt(self.doc.conversion_rate)
+		
+		# TODO validate conversion rate
+		
+		self.item_doclist = self.doclist.get({"parentfield": self.fname})
+		self.tax_doclist = self.doclist.get({"parentfield": self.other_fname})
+		
+		self.calculate_item_values()
+		self.initialize_taxes()
+		
+		if hasattr(self, "determine_exclusive_rate"):
+			self.determine_exclusive_rate()
+		
+		self.calculate_net_total()
+		self.calculate_taxes()
+		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
+			
+			self.validate_on_previous_row(tax)
+			self.validate_inclusive_tax(tax)
+			self.round_floats_in(tax)
+			
+	def validate_on_previous_row(self, tax):
+		"""
+			validate if a valid row id is mentioned in case of
+			On Previous Row Amount and On Previous Row Total
+		"""
+		if tax.charge_type in ["On Previous Row Amount", "On Previous Row Total"] and \
+				(not tax.row_id or cint(tax.row_id) >= tax.idx):
+			msgprint((_("Row") + " # %(idx)s [%(taxes_doctype)s]: " + \
+				_("Please specify a valid") + " %(row_id_label)s") % {
+					"idx": tax.idx,
+					"taxes_doctype": tax.doctype,
+					"row_id_label": self.meta.get_label("row_id",
+						parentfield=self.other_fname)
+				}, raise_exception=True)
+				
+	def validate_inclusive_tax(self, tax):
+		def _on_previous_row_error(row_range):
+			msgprint((_("Row") + " # %(idx)s [%(doctype)s]: " +
+				_("to be included in Item's rate, it is required that: ") +
+				" [" + _("Row") + " # %(row_range)s] " + _("also be included in Item's rate")) % {
+					"idx": tax.idx,
+					"doctype": tax.doctype,
+					"inclusive_label": self.meta.get_label("included_in_print_rate",
+						parentfield=self.other_fname),
+					"charge_type_label": self.meta.get_label("charge_type",
+						parentfield=self.other_fname),
+					"charge_type": tax.charge_type,
+					"row_range": row_range
+				}, raise_exception=True)
+		
+		if cint(tax.included_in_print_rate):
+			if tax.charge_type == "Actual":
+				# inclusive tax cannot be of type Actual
+				msgprint((_("Row") 
+					+ " # %(idx)s [%(doctype)s]: %(charge_type_label)s = \"%(charge_type)s\" " 
+					+ "cannot be included in Item's rate") % {
+						"idx": tax.idx,
+						"doctype": tax.doctype,
+						"charge_type_label": self.meta.get_label("charge_type",
+							parentfield=self.other_fname),
+						"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):
+				# 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]]):
+				# 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:
+			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)
+				
+				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
+				
+				# store tax breakup for each item
+				tax.item_wise_tax_detail[item.item_code] = current_tax_amount
+				
+				if tax.category:
+					# if just for valuation, do not add the tax amount in total
+					# hence, setting it as 0 for further steps
+					current_tax_amount = 0.0 if (tax.category == "Valuation") else current_tax_amount
+					
+					current_tax_amount *= -1.0 if (tax.add_deduct_tax == "Deduct") else 1.0
+				
+				# Calculate tax.total viz. grand total till that step
+				# 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))
+						
+				else:
+					tax.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
+				
+	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
+
+		if tax.charge_type == "Actual":
+			# distribute the tax amount proportionally to each item row
+			actual = flt(tax.rate, self.precision("tax_amount", tax))
+			current_tax_amount = (self.doc.net_total
+				and ((item.amount / self.doc.net_total) * actual)
+				or 0)
+		elif tax.charge_type == "On Net Total":
+			current_tax_amount = (tax_rate / 100.0) * item.amount
+		elif tax.charge_type == "On Previous Row Amount":
+			current_tax_amount = (tax_rate / 100.0) * \
+				self.tax_doclist[cint(tax.row_id) - 1].tax_amount_for_current_item
+		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
+
+		return flt(current_tax_amount, self.precision("tax_amount", tax))
+		
+	def _load_item_tax_rate(self, item_tax_rate):
+		return json.loads(item_tax_rate) if item_tax_rate else {}
+		
+	def _get_tax_rate(self, tax, item_tax_map):
+		if item_tax_map.has_key(tax.account_head):
+			return flt(item_tax_map.get(tax.account_head), self.precision("rate", tax))
+		else:
+			return tax.rate
+	
+	def _cleanup(self):
+		for tax in self.tax_doclist:
+			for fieldname in ("grand_total_for_current_item",
+				"tax_amount_for_current_item",
+				"tax_fraction_for_current_item", 
+				"grand_total_fraction_for_current_item"):
+				if fieldname in tax.fields:
+					del tax.fields[fieldname]
+			
+			tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail)
+			
+	def _set_in_company_currency(self, item, print_field, base_field):
+		"""set values in base currency"""
+		item.fields[base_field] = flt((flt(item.fields[print_field],
+			self.precision(print_field, item)) * self.doc.conversion_rate),
+			self.precision(base_field, item))
 
 	def get_gl_dict(self, args, cancel=None):
 		"""this method populates the common properties of a gl entry record"""
diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py
index 1fc411f..8313b54 100644
--- a/controllers/buying_controller.py
+++ b/controllers/buying_controller.py
@@ -17,34 +17,45 @@
 from __future__ import unicode_literals
 import webnotes
 from webnotes import _, msgprint
-from webnotes.utils import flt, cint
-import json
+from webnotes.utils import flt
 
 from buying.utils import get_item_details
 from setup.utils import get_company_currency
-from utilities.transaction_base import validate_conversion_rate
 
 from controllers.stock_controller import StockController
 
 class WrongWarehouseCompany(Exception): pass
 
 class BuyingController(StockController):
+	def onload_post_render(self):
+		self.set_price_list_currency("buying")
+
+		# contact, address, item details
+		self.set_missing_values()
+		
+		self.set_taxes("Purchase Taxes and Charges", "purchase_tax_details", "purchase_other_charges")
+	
 	def validate(self):
 		super(BuyingController, self).validate()
 		self.validate_stock_or_nonstock_items()
 		self.validate_warehouse_belongs_to_company()
 		
-		if self.meta.get_field("currency"):
-			self.company_currency = get_company_currency(self.doc.company)
-			validate_conversion_rate(self.doc.currency, self.doc.conversion_rate,
-				self.meta.get_label("conversion_rate"), self.doc.company)
-			
-			# IMPORTANT: enable this only when client side code is similar to this one
-			# self.calculate_taxes_and_totals()
+	def set_missing_values(self, for_validate=False):
+		# set contact and address details for supplier, if they are not mentioned
+		if self.doc.supplier and not (self.doc.contact_person and self.doc.supplier_address):
+			for fieldname, val in self.get_default_address_and_contact("supplier").items():
+				if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname):
+					self.doc.fields[fieldname] = val
+		
+		self.set_missing_item_details(get_item_details)
+		
+	def set_supplier_defaults(self):
+		self.get_default_supplier_address()
 						
-			# set total in words
-			self.set_total_in_words()
-	
+	def get_purchase_tax_details(self):
+		self.doclist = self.doc.clear_table(self.doclist, "purchase_tax_details")
+		self.set_taxes()
+			
 	def validate_warehouse_belongs_to_company(self):
 		for warehouse, company in webnotes.conn.get_values("Warehouse", 
 			self.doclist.get_distinct_values("warehouse"), "company").items():
@@ -70,24 +81,6 @@
 				webnotes.msgprint(_("""Tax Category can not be 'Valuation' or 'Valuation and Total' 
 					as all items are non-stock items"""), raise_exception=1)
 			
-	def update_item_details(self):
-		for item in self.doclist.get({"parentfield": self.fname}):
-			ret = get_item_details({
-				"doctype": self.doc.doctype,
-				"docname": self.doc.name,
-				"item_code": item.item_code,
-				"warehouse": item.warehouse,
-				"supplier": self.doc.supplier,
-				"transaction_date": self.doc.posting_date,
-				"conversion_rate": self.doc.conversion_rate,
-				"price_list_name": self.doc.price_list_name,
-				"price_list_currency": self.doc.price_list_currency,
-				"plc_conversion_rate": self.doc.plc_conversion_rate
-			})
-			for r in ret:
-				if not item.fields.get(r):
-					item.fields[r] = ret[r]
-	
 	def set_total_in_words(self):
 		from webnotes.utils import money_in_words
 		company_currency = get_company_currency(self.doc.company)
@@ -98,26 +91,11 @@
 		 		self.doc.currency)
 		
 	def calculate_taxes_and_totals(self):
-		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": "purchase_tax_details"})
-		
-		self.calculate_item_values()
-		self.initialize_taxes()
-		self.calculate_net_total()
-		self.calculate_taxes()
-		self.calculate_totals()
+		self.other_fname = "purchase_tax_details"
+		super(BuyingController, self).calculate_taxes_and_totals()
 		self.calculate_outstanding_amount()
 		
-		self._cleanup()
-		
 	def calculate_item_values(self):
-		def _set_base(item, print_field, base_field):
-			"""set values in base currency"""
-			item.fields[base_field] = flt((flt(item.fields[print_field],
-				self.precision(print_field, item)) * self.doc.conversion_rate),
-				self.precision(base_field, item))
-		
 		# hack! - cleaned up in _cleanup()
 		if self.doc.doctype != "Purchase Invoice":
 			df = self.meta.get_field("purchase_rate", parentfield=self.fname)
@@ -130,119 +108,36 @@
 				
 			self.round_floats_in(item)
 
-			if item.discount_rate == 100:
-				item.import_ref_rate = item.import_ref_rate or item.import_rate
-				item.import_rate = 0
-			else:
-				if item.import_ref_rate:
-					item.import_rate = flt(item.import_ref_rate * (1.0 - (item.discount_rate / 100.0)),
-						self.precision("import_rate", item))
-				else:
-					# assume that print rate and discount_rate are specified
-					item.import_ref_rate = flt(item.import_rate / (1.0 - (item.discount_rate / 100.0)),
-						self.precision("import_ref_rate", item))
+			if item.discount_rate == 100.0:
+				item.import_rate = 0.0
+			elif item.import_ref_rate:
+				item.import_rate = flt(item.import_ref_rate * (1.0 - (item.discount_rate / 100.0)),
+					self.precision("import_rate", item))
 						
 			item.import_amount = flt(item.import_rate * item.qty,
 				self.precision("import_amount", item))
+			item.item_tax_amount = 0.0;
 				
-			_set_base(item, "import_ref_rate", "purchase_ref_rate")
-			_set_base(item, "import_rate", "rate")
-			_set_base(item, "import_amount", "amount")
+			self._set_in_company_currency(item, "import_ref_rate", "purchase_ref_rate")
+			self._set_in_company_currency(item, "import_rate", "rate")
+			self._set_in_company_currency(item, "import_amount", "amount")
 			
-	def initialize_taxes(self):
-		for tax in self.tax_doclist:
-			# initialize totals to 0
-			tax.tax_amount = tax.total = 0.0
-			
-			# temporary fields
-			tax.tax_amount_for_current_item = tax.grand_total_for_current_item = 0.0
-			
-			tax.item_wise_tax_detail = {}
-			
-			self.validate_on_previous_row(tax)
-			
-			self.round_floats_in(tax)
-		
 	def calculate_net_total(self):
-		self.doc.net_total = 0
-		self.doc.net_total_import = 0
+		self.doc.net_total = self.doc.net_total_import = 0.0
 
 		for item in self.item_doclist:
 			self.doc.net_total += item.amount
 			self.doc.net_total_import += item.import_amount
 			
-		self.doc.net_total = flt(self.doc.net_total, self.precision("net_total"))
-		self.doc.net_total_import = flt(self.doc.net_total_import,
-			self.precision("net_total_import"))
-		
-	def calculate_taxes(self):
-		for item in self.item_doclist:
-			item_tax_map = self._load_item_tax_rate(item.item_tax_rate)
-			item.item_tax_amount = 0
-
-			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)
-
-				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 not (current_tax_amount or self.doc.net_total or tax.tax_amount) and \
-						tax.charge_type=="Actual":
-					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 += tax.tax_amount_for_current_item
-
-				if tax.category == "Valuation":
-					# if just for valuation, do not add the tax amount in total
-					# hence, setting it as 0 for further steps
-					current_tax_amount = 0
-				else:
-					current_tax_amount *= tax.add_deduct_tax == "Deduct" and -1.0 or 1.0
-
-				# Calculate tax.total viz. grand total till that step
-				# 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))
-
-				else:
-					tax.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
-
-				# store tax_breakup for each item
-				# DOUBT: should valuation type amount also be stored?
-				tax.item_wise_tax_detail[item.item_code] = current_tax_amount
+		self.round_floats_in(self.doc, ["net_total", "net_total_import"])
 		
 	def calculate_totals(self):
-		if self.tax_doclist:
-			self.doc.grand_total = flt(self.tax_doclist[-1].total,
-				self.precision("grand_total"))
-			self.doc.grand_total_import = flt(
-				self.doc.grand_total / self.doc.conversion_rate,
-				self.precision("grand_total_import"))
-		else:
-			self.doc.grand_total = flt(self.doc.net_total,
-				self.precision("grand_total"))
-			self.doc.grand_total_import = flt(
-				self.doc.grand_total / self.doc.conversion_rate,
-				self.precision("grand_total_import"))
+		self.doc.grand_total = flt(self.tax_doclist and \
+			self.tax_doclist[-1].total or self.doc.net_total, self.precision("grand_total"))
+		self.doc.grand_total_import = flt(self.doc.grand_total / self.doc.conversion_rate,
+			self.precision("grand_total_import"))
 
-		self.doc.total_tax = \
-			flt(self.doc.grand_total - self.doc.net_total,
+		self.doc.total_tax = flt(self.doc.grand_total - self.doc.net_total,
 			self.precision("total_tax"))
 
 		if self.meta.get_field("rounded_total"):
@@ -261,68 +156,18 @@
 				self.precision("outstanding_amount"))
 			
 	def _cleanup(self):
-		for tax in self.tax_doclist:
-			del tax.fields["grand_total_for_current_item"]
-			del tax.fields["tax_amount_for_current_item"]
-			tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail)
-		
-		# except in purchase invoice, rate field is purchase_rate
-		if self.doc.doctype != "Purchase Invoice":
-			for item in self.item_doclist:
-				item.purchase_rate = item.rate
-				del item.fields["rate"]
-				
+		super(BuyingController, self)._cleanup()
+			
+		# 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)
 			df.fieldname = "purchase_rate"
-				
-	def validate_on_previous_row(self, tax):
-		"""
-			validate if a valid row id is mentioned in case of
-			On Previous Row Amount and On Previous Row Total
-		"""
-		if tax.charge_type in ["On Previous Row Amount", "On Previous Row Total"] and \
-				(not tax.row_id or cint(tax.row_id) >= tax.idx):
-			msgprint((_("Row") + " # %(idx)s [%(taxes_doctype)s]: " + \
-				_("Please specify a valid") + " %(row_id_label)s") % {
-					"idx": tax.idx,
-					"taxes_doctype": tax.parenttype,
-					"row_id_label": self.meta.get_label("row_id",
-						parentfield="purchase_tax_details")
-				}, raise_exception=True)
-				
-	def _load_item_tax_rate(self, item_tax_rate):
-		if not item_tax_rate:
-			return {}
-		return json.loads(item_tax_rate)
-		
-	def get_current_tax_amount(self, item, tax, item_tax_map):
-		tax_rate = self._get_tax_rate(tax, item_tax_map)
-
-		if tax.charge_type == "Actual":
-			# distribute the tax amount proportionally to each item row
-			actual = flt(tax.rate, self.precision("tax_amount", tax))
-			current_tax_amount = (self.doc.net_total
-				and ((item.amount / self.doc.net_total) * actual)
-				or 0)
-		elif tax.charge_type == "On Net Total":
-			current_tax_amount = (tax_rate / 100.0) * item.amount
-		elif tax.charge_type == "On Previous Row Amount":
-			current_tax_amount = (tax_rate / 100.0) * \
-				self.tax_doclist[cint(tax.row_id) - 1].tax_amount_for_current_item
-		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
-
-		return flt(current_tax_amount, self.precision("tax_amount", tax))
-		
-	def _get_tax_rate(self, tax, item_tax_map):
-		if item_tax_map.has_key(tax.account_head):
-			return flt(item_tax_map.get(tax.account_head), self.precision("rate", tax))
-		else:
-			return tax.rate
 			
+			for item in self.item_doclist:
+				item.purchase_rate = item.rate
+				del item.fields["rate"]
+				
 	def set_item_tax_amount(self, item, tax, current_tax_amount):
 		"""
 			item_tax_amount is the total tax amount applied on that item
@@ -330,10 +175,8 @@
 			
 			TODO: rename item_tax_amount to valuation_tax_amount
 		"""
-		if tax.category in ["Valuation", "Valuation and Total"] and \
-				item.item_code in self.stock_items:
-			item.item_tax_amount += flt(current_tax_amount,
-				self.precision("item_tax_amount", item))
+		if tax.category in ["Valuation", "Valuation and Total"]:
+			item.item_tax_amount += flt(current_tax_amount, self.precision("item_tax_amount", item))
 				
 	# update valuation rate
 	def update_valuation_rate(self, parentfield):
diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py
index 01c8c61..de90fa7 100644
--- a/controllers/selling_controller.py
+++ b/controllers/selling_controller.py
@@ -18,34 +18,20 @@
 import webnotes
 from webnotes.utils import cint, flt, comma_or
 from setup.utils import get_company_currency
+from selling.utils import get_item_details
 from webnotes import msgprint, _
-import json
 
 from controllers.stock_controller import StockController
 
 class SellingController(StockController):
 	def onload_post_render(self):
-		self.set_price_list_currency()
+		self.set_price_list_currency("selling")
 
 		# contact, address, item details and pos details (if applicable)
 		self.set_missing_values()
 		
-		if self.meta.get_field("other_charges"):
-			self.set_taxes()
+		self.set_taxes("Sales Taxes and Charges", "other_charges", "charge")
 			
-	def validate(self):
-		super(SellingController, self).validate()
-		# self.calculate_taxes_and_totals()
-		self.set_total_in_words()
-		self.set_missing_values(for_validate=True)
-		
-	def set_price_list_currency(self):
-		if self.doc.price_list_name and not self.doc.price_list_currency:
-			# TODO - change this, since price list now has only one currency allowed
-			from setup.utils import get_price_list_currency
-			self.doc.fields.update(get_price_list_currency(
-				{"price_list_name": self.doc.price_list_name, "use_for": "selling"}))
-		
 	def set_missing_values(self, for_validate=False):
 		# set contact and address details for customer, if they are not mentioned
 		if self.doc.customer and not (self.doc.contact_person and self.doc.customer_address):
@@ -53,42 +39,11 @@
 				if not self.doc.fields.get(fieldname) and self.meta.get_field(fieldname):
 					self.doc.fields[fieldname] = val
 					
-		# set missing item values
-		from selling.utils import get_item_details
-		for item in self.doclist.get({"parentfield": "entries"}):
-			if item.fields.get("item_code"):
-				args = item.fields.copy().update(self.doc.fields)
-				ret = get_item_details(args)
-				for fieldname, value in ret.items():
-					if self.meta.get_field(fieldname, parentfield="entries") and \
-						not item.fields.get(fieldname):
-							item.fields[fieldname] = value
+		self.set_missing_item_details(get_item_details)
 							
-	def set_taxes(self):
-		if not self.doclist.get({"parentfield": "other_charges"}):
-			if not self.doc.charge:
-				# get the default tax master
-				self.doc.charge = webnotes.conn.get_value("Sales Taxes and Charges Master",
-					{"is_default": 1})
-			
-			if self.doc.charge:
-				from webnotes.model import default_fields
-				tax_master = webnotes.bean("Sales Taxes and Charges Master", self.doc.charge)
-				for i, tax in enumerate(tax_master.doclist.get({"parentfield": "other_charges"})):
-					for fieldname in default_fields:
-						tax.fields[fieldname] = None
-					
-					tax.fields.update({
-						"doctype": "Sales Taxes and Charges",
-						"parentfield": "other_charges",
-						"idx": i+1
-					})
-					
-					self.doclist.append(tax)
-					
 	def get_other_charges(self):
 		self.doclist = self.doc.clear_table(self.doclist, "other_charges")
-		self.set_taxes()
+		self.set_taxes("Sales Taxes and Charges", "other_charges", "charge")
 		
 	def set_customer_defaults(self):
 		self.get_default_customer_address()
@@ -140,24 +95,14 @@
 				raise_exception=1)
 				
 	def calculate_taxes_and_totals(self):
-		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": "other_charges"})
+		self.other_fname = "other_charges"
 		
-		self.calculate_item_values()
-		self.initialize_taxes()
-		self.determine_exclusive_rate()
-		self.calculate_net_total()
-		self.calculate_taxes()
-		self.calculate_totals()
+		super(SellingController, self).calculate_taxes_and_totals()
+		
 		self.calculate_commission()
 		self.calculate_contribution()
 		# self.calculate_outstanding_amount()
-		self._cleanup()
-		
-		# TODO
-		# print format: show net_total_export instead of net_total
-		
+				
 	def determine_exclusive_rate(self):
 		if not any((cint(tax.included_in_print_rate) for tax in self.tax_doclist)):
 			# no inclusive tax
@@ -215,45 +160,21 @@
 		return current_tax_fraction
 		
 	def calculate_item_values(self):
-		def _set_base(item, print_field, base_field):
-			"""set values in base currency"""
-			item.fields[base_field] = flt((flt(item.fields[print_field],
-				self.precision(print_field, item)) * self.doc.conversion_rate),
-				self.precision(base_field, item))
-
 		for item in self.item_doclist:
 			self.round_floats_in(item)
 			
 			if item.adj_rate == 100:
-				item.ref_rate = item.ref_rate or item.export_rate
 				item.export_rate = 0
-			else:
-				if item.ref_rate:
-					item.export_rate = flt(item.ref_rate * (1.0 - (item.adj_rate / 100.0)),
-						self.precision("export_rate", item))
-				else:
-					# assume that print rate and discount are specified
-					item.ref_rate = flt(item.export_rate / (1.0 - (item.adj_rate / 100.0)),
-						self.precision("ref_rate", item))
+			elif item.ref_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))
 				
-			_set_base(item, "ref_rate", "base_ref_rate")
-			_set_base(item, "export_rate", "basic_rate")
-			_set_base(item, "export_amount", "amount")
-	
-	def initialize_taxes(self):
-		for tax in self.tax_doclist:
-			tax.tax_amount = tax.total = 0.0
-			tax.item_wise_tax_detail = {}
-
-			# temporary fields
-			tax.tax_amount_for_current_item = tax.grand_total_for_current_item = 0.0
-			
-			self.validate_on_previous_row(tax)
-			self.validate_inclusive_tax(tax)
-			self.round_floats_in(tax)
+			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
@@ -263,47 +184,6 @@
 			self.doc.net_total_export += item.export_amount
 		
 		self.round_floats_in(self.doc, ["net_total", "net_total_export"])
-		
-	def calculate_taxes(self):
-		for item in 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)
-
-				# 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
-				
-				# Calculate tax.total viz. grand total till that step
-				# 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))
-						
-				else:
-					tax.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
-
-				# store tax breakup for each item
-				tax.item_wise_tax_detail[item.item_code] = current_tax_amount
 				
 	def calculate_totals(self):
 		self.doc.grand_total = flt(self.tax_doclist and \
@@ -344,98 +224,6 @@
 			msgprint(_("Total") + " " + 
 				_(self.meta.get_label("allocated_percentage", parentfield="sales_team")) + 
 				" " + _("should be 100%"), raise_exception=True)
-	
-	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
-
-		if tax.charge_type == "Actual":
-			# distribute the tax amount proportionally to each item row
-			actual = flt(tax.rate, self.precision("tax_amount", tax))
-			current_tax_amount = (self.doc.net_total
-				and ((item.amount / self.doc.net_total) * actual)
-				or 0)
-		elif tax.charge_type == "On Net Total":
-			current_tax_amount = (tax_rate / 100.0) * item.amount
-		elif tax.charge_type == "On Previous Row Amount":
-			current_tax_amount = (tax_rate / 100.0) * \
-				self.tax_doclist[cint(tax.row_id) - 1].tax_amount_for_current_item
-		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
-
-		return flt(current_tax_amount, self.precision("tax_amount", tax))
-	
-	def validate_on_previous_row(self, tax):
-		"""
-			validate if a valid row id is mentioned in case of
-			On Previous Row Amount and On Previous Row Total
-		"""
-		if tax.charge_type in ["On Previous Row Amount", "On Previous Row Total"] and \
-				(not tax.row_id or cint(tax.row_id) >= tax.idx):
-			msgprint((_("Row") + " # %(idx)s [%(taxes_doctype)s]: " + \
-				_("Please specify a valid") + " %(row_id_label)s") % {
-					"idx": tax.idx,
-					"taxes_doctype": tax.doctype,
-					"row_id_label": self.meta.get_label("row_id",
-						parentfield="other_charges")
-				}, raise_exception=True)
-				
-	def validate_inclusive_tax(self, tax):
-		def _on_previous_row_error(row_range):
-			msgprint((_("Row") + " # %(idx)s [%(doctype)s]: " +
-				_("to be included in Item's rate, it is required that: ") +
-				" [" + _("Row") + " # %(row_range)s] " + _("also be included in Item's rate")) % {
-					"idx": tax.idx,
-					"doctype": tax.doctype,
-					"inclusive_label": self.meta.get_label("included_in_print_rate",
-						parentfield="other_charges"),
-					"charge_type_label": self.meta.get_label("charge_type",
-						parentfield="other_charges"),
-					"charge_type": tax.charge_type,
-					"row_range": row_range
-				}, raise_exception=True)
-		
-		if cint(tax.included_in_print_rate):
-			if tax.charge_type == "Actual":
-				# inclusive tax cannot be of type Actual
-				msgprint((_("Row") 
-					+ " # %(idx)s [%(doctype)s]: %(charge_type_label)s = \"%(charge_type)s\" " 
-					+ "cannot be included in Item's rate") % {
-						"idx": tax.idx,
-						"doctype": tax.doctype,
-						"charge_type_label": self.meta.get_label("charge_type",
-							parentfield="other_charges"),
-						"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):
-				# 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]]):
-				# all rows about the reffered tax should be inclusive
-				_on_previous_row_error("1 - %d" % (tax.row_id,))
-				
-	def _load_item_tax_rate(self, item_tax_rate):
-		return json.loads(item_tax_rate) if item_tax_rate else {}
-		
-	def _get_tax_rate(self, tax, item_tax_map):
-		if item_tax_map.has_key(tax.account_head):
-			return flt(item_tax_map.get(tax.account_head), self.precision("rate", tax))
-		else:
-			return tax.rate
-				
-	def _cleanup(self):
-		for tax in self.tax_doclist:
-			for fieldname in ("grand_total_for_current_item",
-				"tax_amount_for_current_item",
-				"tax_fraction_for_current_item", 
-				"grand_total_fraction_for_current_item"):
-				if fieldname in tax.fields:
-					del tax.fields[fieldname]
-			
-			tax.item_wise_tax_detail = json.dumps(tax.item_wise_tax_detail)
 			
 	def validate_order_type(self):
 		valid_types = ["Sales", "Maintenance"]
diff --git a/public/js/transaction.js b/public/js/transaction.js
new file mode 100644
index 0000000..34e10f6
--- /dev/null
+++ b/public/js/transaction.js
@@ -0,0 +1,443 @@
+// ERPNext - web based ERP (http://erpnext.com)
+// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+wn.provide("erpnext");
+
+erpnext.TransactionController = wn.ui.form.Controller.extend({
+	onload: function() {
+		if(this.frm.doc.__islocal) {
+			var me = this,
+				today = get_today(),
+				currency = wn.defaults.get_default("currency");
+			
+			$.each({
+				"posting_date": today,
+				"due_date": today,
+				"transaction_date": today,
+				"currency": currency,
+				"price_list_currency": currency,
+				"status": "Draft",
+				"fiscal_year": wn.defaults.get_default("fiscal_year"),
+				"is_subcontracted": "No",
+				"conversion_rate": 1.0,
+				"plc_conversion_rate": 1.0
+			}, function(fieldname, value) {
+				if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname])
+					me.frm.set_value(fieldname, value);
+			});
+		}
+	},
+	
+	refresh: function() {
+		this.frm.clear_custom_buttons();
+		erpnext.hide_naming_series();
+		this.show_item_wise_taxes();
+		
+		if(this.frm.fields_dict.currency)
+			this.currency();
+	},
+	
+	onload_post_render: function() {
+		if(this.frm.doc.__islocal && this.frm.doc.company) {
+			var me = this;
+			this.frm.call({
+				doc: this.frm.doc,
+				method: "onload_post_render",
+				freeze: true,
+				callback: function(r) {
+					// remove this call when using client side mapper
+					me.set_default_values();
+					me.frm.refresh();
+				}
+			});
+		}
+	},
+	
+	company: function() {
+		if(this.frm.doc.company) {
+			var me = this;
+			var company_currency = this.get_company_currency();
+			$.each(["currency", "price_list_currency"], function(i, fieldname) {
+				if(!me.doc[fieldname]) {
+					me.frm.set_value(fieldname, company_currency);
+				}
+			});
+			this.price_list_currency();
+		}
+	},
+	
+	get_company_currency: function() {
+		return erpnext.get_currency(this.frm.doc.company);
+	},
+	
+	currency: function() {
+		this.price_list_currency();
+	},
+	
+	price_list_name: function(use_for) {
+		var me = this;
+		if(this.frm.doc.price_list_name) {
+			this.frm.call({
+				method: "setup.utils.get_price_list_currency",
+				args: {args: {
+					price_list_name: this.frm.doc.price_list_name,
+					use_for: use_for
+				}},
+				callback: function(r) {
+					if(!r.exc) {
+						me.price_list_currency();
+					}
+				}
+			});
+		}
+	},
+	
+	price_list_currency: function() {
+		// What TODO? should we make price list system non-mandatory?
+		this.frm.toggle_reqd("plc_conversion_rate",
+			!!(this.frm.doc.price_list_name && this.frm.doc.price_list_currency));
+		
+		if(this.frm.doc.price_list_currency === this.get_company_currency()) {
+			this.frm.set_value("plc_conversion_rate", 1.0);
+		} else if(this.frm.doc.price_list_currency === this.frm.doc.currency) {
+			this.frm.set_value("plc_conversion_rate", this.frm.doc.conversion_rate);
+		}
+		this.set_dynamic_labels();
+	},
+	
+	plc_conversion_rate: function() {
+		this.price_list_currency();
+	},
+	
+	conversion_rate: function() {
+		this.price_list_currency();
+		this.calculate_taxes_and_totals();
+	},
+	
+	qty: function(doc, cdt, cdn) {
+		this.calculate_taxes_and_totals();
+	},
+	
+	included_in_print_rate: function(doc, cdt, cdn) {
+		var tax = wn.model.get_doc(cdt, cdn);
+		try {
+			this.validate_on_previous_row(tax);
+			this.validate_inclusive_tax(tax);
+			this.calculate_taxes_and_totals();
+		} catch(e) {
+			tax.included_in_print_rate = 0;
+			refresh_field("included_in_print_rate", tax.name, tax.parentfield);
+			throw e;
+		}
+	},
+	
+	validate_on_previous_row: function(tax) {
+		// validate if a valid row id is mentioned in case of
+		// On Previous Row Amount and On Previous Row Total
+		if((["On Previous Row Amount", "On Previous Row Total"].indexOf(tax.charge_type) != -1) &&
+			(!tax.row_id || cint(tax.row_id) >= tax.idx)) {
+				var msg = repl(wn._("Row") + " # %(idx)s [%(doctype)s]: " +
+					wn._("Please specify a valid") + " %(row_id_label)s", {
+						idx: tax.idx,
+						doctype: tax.doctype,
+						row_id_label: wn.meta.get_label(tax.doctype, "row_id", tax.name)
+					});
+				msgprint(msg);
+				throw msg;
+			}
+	},
+	
+	validate_inclusive_tax: function(tax) {
+		if(!this.frm.tax_doclist) this.frm.tax_doclist = this.get_tax_doclist();
+		
+		var actual_type_error = function() {
+			var msg = repl(wn._("For row") + " # %(idx)s [%(doctype)s]: " + 
+				"%(charge_type_label)s = \"%(charge_type)s\" " +
+				wn._("cannot be included in Item's rate"), {
+					idx: tax.idx,
+					doctype: tax.doctype,
+					charge_type_label: wn.meta.get_label(tax.doctype, "charge_type", tax.name),
+					charge_type: tax.charge_type
+				});
+			msgprint(msg);
+			throw msg;
+		};
+		
+		var on_previous_row_error = function(row_range) {
+			var msg = repl(wn._("For row") + " # %(idx)s [%(doctype)s]: " + 
+				wn._("to be included in Item's rate, it is required that: ") + 
+				" [" + wn._("Row") + " # %(row_range)s] " + wn._("also be included in Item's rate"), {
+					idx: tax.idx,
+					doctype: tax.doctype,
+					charge_type_label: wn.meta.get_label(tax.doctype, "charge_type", tax.name),
+					charge_type: tax.charge_type,
+					inclusive_label: wn.meta.get_label(tax.doctype, "included_in_print_rate", tax.name),
+					row_range: row_range,
+				});
+			
+			msgprint(msg);
+			throw msg;
+		};
+		
+		if(cint(tax.included_in_print_rate)) {
+			if(tax.charge_type == "Actual") {
+				// inclusive tax cannot be of type Actual
+				actual_type_error();
+			} else if(tax.charge_type == "On Previous Row Amount" &&
+				!cint(this.frm.tax_doclist[tax.row_id - 1].included_in_print_rate)) {
+					// referred row should also be an inclusive tax
+					on_previous_row_error(tax.row_id);
+			} else if(tax.charge_type == "On Previous Row Total") {
+				var taxes_not_included = $.map(this.frm.tax_doclist.slice(0, tax.row_id), 
+					function(t) { return cint(t.included_in_print_rate) ? null : t; });
+				if(taxes_not_included.length > 0) {
+					// all rows above this tax should be inclusive
+					on_previous_row_error(tax.row_id == 1 ? "1" : "1 - " + tax.row_id);
+				}
+			}
+		}
+	},
+	
+	_load_item_tax_rate: function(item_tax_rate) {
+		return item_tax_rate ? JSON.parse(item_tax_rate) : {};
+	},
+	
+	_get_tax_rate: function(tax, item_tax_map) {
+		return (keys(item_tax_map).indexOf(tax.account_head) != -1) ?
+			flt(item_tax_map[tax.account_head], precision("rate", tax)) :
+			tax.rate;
+	},
+	
+	get_item_wise_taxes_html: function() {
+		var item_tax = {};
+		var tax_accounts = [];
+		var company_currency = this.get_company_currency();
+		
+		$.each(this.get_tax_doclist(), function(i, tax) {
+			var tax_amount_precision = precision("tax_amount", tax);
+			$.each(JSON.parse(tax.item_wise_tax_detail || '{}'), 
+				function(item_code, tax_amount) {
+					if(!item_tax[item_code]) item_tax[item_code] = {};
+					item_tax[item_code][tax.account_head] = flt(tax_amount, tax_amount_precision);
+				});
+			tax_accounts.push(tax.account_head);
+		});
+		
+		var headings = $.map([wn._("Item Name")].concat(tax_accounts), 
+			function(head) { return '<th style="min-width: 100px;">' + (head || "") + "</th>" }).join("\n");
+		
+		var rows = $.map(this.get_item_doclist(), function(item) {
+			var item_tax_record = item_tax[item.item_code || item.item_name];
+			return repl("<tr><td>%(item_name)s</td>%(taxes)s</tr>", {
+				item_name: item.item_name,
+				taxes: $.map(tax_accounts, function(head) {
+					return "<td>" + format_currency(item_tax_record[head], company_currency) + "</td>"
+				}).join("\n")
+			});
+		}).join("\n");
+		
+		return '<div style="overflow-x: scroll;"><table class="table table-bordered table-hover">\
+			<thead><tr>' + headings + '</tr></thead> \
+			<tbody>' + rows + '</tbody> \
+		</table></div>';
+	},
+	
+	set_default_values: function() {
+		$.each(wn.model.get_doclist(this.frm.doctype, this.frm.docname), function(i, doc) {
+			var updated = wn.model.set_default_values(doc);
+			if(doc.parentfield) {
+				refresh_field(doc.parentfield);
+			} else {
+				refresh_field(updated);
+			}
+		});
+	},
+	
+	validate_company_and_party: function(party_field) {
+		var valid = true;
+		$.each(["company", party_field], function(i, fieldname) {
+			if(!me.frm.doc[fieldname]) {
+				valid = false;
+				msgprint(wn._("Please specify") + ": " + 
+					wn.meta.get_label(me.frm.doc.doctype, fieldname, me.frm.doc.name) + 
+					". " + wn._("It is needed to fetch Item Details."));
+			}
+		});
+		return valid;
+	},
+	
+	get_item_doclist: function() {
+		return wn.model.get_doclist(this.frm.doc.doctype, this.frm.doc.name,
+			{parentfield: this.fname});
+	},
+	
+	get_tax_doclist: function() {
+		return wn.model.get_doclist(this.frm.doc.doctype, this.frm.doc.name,
+			{parentfield: this.other_fname});
+	},
+	
+	validate_conversion_rate: function() {
+		this.frm.doc.conversion_rate = flt(this.frm.doc.conversion_rate, precision("conversion_rate"));
+		var conversion_rate_label = wn.meta.get_label(this.frm.doc.doctype, "conversion_rate", 
+			this.frm.doc.name);
+		
+		if(this.frm.doc.conversion_rate == 0) {
+			wn.throw(wn._(conversion_rate_label) + " " + wn._("cannot be 0"));
+		}
+		
+		var company_currency = this.get_company_currency();
+		var valid_conversion_rate = conversion_rate ?
+			((this.frm.doc.currency == company_currency && this.frm.doc.conversion_rate == 1.0) ||
+			(this.frm.doc.currency != company_currency && this.frm.doc.conversion_rate != 1.0)) :
+			false;
+		
+		if(!valid_conversion_rate) {
+			wn.throw(wn._("Please enter valid") + " " + wn._(conversion_rate_label) + 
+				" 1 " + this.frm.doc.currency + " = [?] " + company_currency);
+		}
+	},
+	
+	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();
+		this.calculate_net_total();
+		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_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 });
+			
+			me.validate_on_previous_row(tax);
+			me.validate_inclusive_tax(tax);
+			wn.model.round_floats_in(tax);
+		});
+	},
+	
+	calculate_taxes: function() {
+		var me = this;
+		
+		$.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;
+					}
+				
+				// 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;
+				
+				// store tax breakup for each item
+				tax.item_wise_tax_detail[item.item_code || item.item_name] = current_tax_amount;
+				
+				// for buying
+				if(tax.category) {
+					// if just for valuation, do not add the tax amount in total
+					// hence, setting it as 0 for further steps
+					current_tax_amount = (tax.category == "Valuation") ? 0.0 : current_tax_amount;
+					
+					current_tax_amount *= (tax.add_deduct_tax == "Deduct") ? -1.0 : 1.0;
+				}
+				
+				// Calculate tax.total viz. grand total till that step
+				// 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,
+						precision("total", tax));
+				} else {
+					tax.grand_total_for_current_item = 
+						flt(me.frm.tax_doclist[i-1].grand_total_for_current_item + current_tax_amount,
+							precision("total", tax));
+				}
+				
+				// in tax.total, accumulate grand total for each item
+				tax.total += tax.grand_total_for_current_item;
+			});
+		});
+	},
+	
+	get_current_tax_amount: function(item, tax, item_tax_map) {
+		var tax_rate = this._get_tax_rate(tax, item_tax_map);
+		var current_tax_amount = 0.0;
+		
+		if(tax.charge_type == "Actual") {
+			// distribute the tax amount proportionally to each item row
+			var actual = flt(tax.rate, precision("tax_amount", tax));
+			current_tax_amount = this.frm.doc.net_total ?
+				((item.amount / this.frm.doc.net_total) * actual) :
+				0.0;
+			
+		} else if(tax.charge_type == "On Net Total") {
+			current_tax_amount = (tax_rate / 100.0) * item.amount;
+			
+		} else if(tax.charge_type == "On Previous Row Amount") {
+			current_tax_amount = (tax_rate / 100.0) *
+				this.frm.tax_doclist[cint(tax.row_id) - 1].tax_amount_for_current_item;
+			
+		} 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;
+			
+		}
+		
+		return flt(current_tax_amount, precision("tax_amount", tax));
+	},
+	
+	_cleanup: function() {
+		$.each(this.frm.tax_doclist, function(i, tax) {
+			$.each(["tax_amount_for_current_item", "grand_total_for_current_item",
+				"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"], 
+				function(i, fieldname) { delete tax[fieldname]; });
+			
+			tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail);
+		});
+	},
+	
+	_set_in_company_currency: function(item, print_field, base_field) {
+		// set values in base currency
+		item[base_field] = flt(item[print_field] * this.frm.doc.conversion_rate,
+			precision(base_field, item));
+	},
+});
\ No newline at end of file
diff --git a/selling/doctype/quotation/quotation.js b/selling/doctype/quotation/quotation.js
index 078baf1..a7c5421 100644
--- a/selling/doctype/quotation/quotation.js
+++ b/selling/doctype/quotation/quotation.js
@@ -53,14 +53,6 @@
 	}
 }
 
-cur_frm.cscript.onload_post_render = function(doc, dt, dn) {
-	var callback = function(doc, dt, dn) {
-		// defined in sales_common.js
-		cur_frm.cscript.update_item_details(doc, dt, dn);
-	}
-	cur_frm.cscript.hide_price_list_currency(doc, dt, dn, callback); 
-}
-
 // hide - unhide fields based on lead or customer..
 // =======================================================================================================================
 cur_frm.cscript.lead_cust_show = function(doc,cdt,cdn){
diff --git a/selling/doctype/sales_common/sales_common.js b/selling/doctype/sales_common/sales_common.js
index fd3f5c5..4d97034 100644
--- a/selling/doctype/sales_common/sales_common.js
+++ b/selling/doctype/sales_common/sales_common.js
@@ -22,61 +22,19 @@
 // cur_frm.cscript.sales_team_fname - Sales Team fieldname
 
 wn.provide("erpnext.selling");
+wn.require("app/js/transaction.js");
 
-erpnext.selling.SellingController = wn.ui.form.Controller.extend({
+erpnext.selling.SellingController = erpnext.TransactionController.extend({
 	setup: function() {
 		this.frm.add_fetch("sales_partner", "commission_rate", "commission_rate");
 	},
 	
-	// events when rendering form
 	// 1
 	onload: function() {
-		var me = this;
+		this._super();
 		this.toggle_rounded_total();
-		if(this.frm.doc.__islocal) {
-			// set date fields
-			$.each(["posting_date", "due_date", "transaction_date"], function(i, fieldname) {
-				if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname]) {
-					me.frm.set_value(fieldname, get_today());
-				}
-			});
-			
-			// set currency fields
-			$.each(["currency", "price_list_currency"], function(i, fieldname) {
-				if(me.frm.fields_dict[fieldname] && !me.frm.doc[fieldname]) {
-					me.frm.set_value(fieldname, wn.defaults.get_default("currency"));
-				}
-			});
-			
-			// status
-			if(!this.frm.doc.status) this.frm.set_value("status", "Draft");
-			
-			// TODO set depends_on for customer related fields
-		}
-	},
-	
-	// 2
-	refresh: function() {
-		erpnext.hide_naming_series();
-		this.show_item_wise_taxes();
-		this.set_dynamic_labels();
-	},
-	
-	// 3
-	onload_post_render: function() {
-		if(this.frm.doc.__islocal && this.frm.doc.company) {
-			var me = this;
-			this.frm.call({
-				doc: this.frm.doc,
-				method: "onload_post_render",
-				freeze: true,
-				callback: function(r) {
-					// remove this call when using client side mapper
-					me.set_default_values();
-					me.frm.refresh();
-				}
-			});
-		}
+		
+		// TODO set depends_on for customer related fields
 	},
 	
 	validate: function() {
@@ -85,6 +43,32 @@
 		// TODO calc adjustment amount
 	},
 	
+	customer: function() {
+		if(this.frm.doc.customer || this.frm.doc.debit_to) {
+			if(!this.frm.doc.company) {
+				this.frm.set_value("customer", null);
+				msgprint(wn._("Please specify Company"));
+			} else {
+				var me = this;
+				var price_list_name = this.frm.doc.price_list_name;
+
+				this.frm.call({
+					doc: this.frm.doc,
+					method: "set_customer_defaults",
+					freeze: true,
+					callback: function(r) {
+						if(!r.exc) {
+							me.frm.refresh_fields();
+							if(me.frm.doc.price_list_name !== price_list_name) me.price_list_name();
+						}
+					}
+				});
+			}
+		}
+		
+		// TODO hide/unhide related fields
+	},
+	
 	barcode: function(doc, cdt, cdn) {
 		this.item_code(doc, cdt, cdn);
 	},
@@ -93,7 +77,7 @@
 		var me = this;
 		var item = wn.model.get_doc(cdt, cdn);
 		if(item.item_code || item.barcode) {
-			if(!this.validate_company_and_party()) {
+			if(!this.validate_company_and_party("customer")) {
 				item.item_code = null;
 				refresh_field("item_code", item.name, item.parentfield);
 			} else {
@@ -128,90 +112,8 @@
 		}
 	},
 	
-	company: function() {
-		if(this.frm.doc.company) {
-			var me = this;
-			var company_currency = this.get_company_currency();
-			$.each(["currency", "price_list_currency"], function(i, fieldname) {
-				if(!me.doc[fieldname]) {
-					me.frm.set_value(fieldname, company_currency);
-				}
-			});
-			this.price_list_currency();
-		}
-	},
-	
-	customer: function() {
-		if(this.frm.doc.customer || this.frm.doc.debit_to) {
-			if(!this.frm.doc.company) {
-				this.frm.set_value("customer", null);
-				msgprint(wn._("Please specify Company"));
-			} else {
-				var me = this;
-				var price_list_name = this.frm.doc.price_list_name;
-
-				this.frm.call({
-					doc: this.frm.doc,
-					method: "set_customer_defaults",
-					freeze: true,
-					callback: function(r) {
-						if(!r.exc) {
-							me.frm.refresh_fields();
-							if(me.frm.doc.price_list_name !== price_list_name) me.price_list_name();
-						}
-					}
-				});
-			}
-		}
-		
-		// TODO hide/unhide related fields
-	},
-	
 	price_list_name: function() {
-		var me = this;
-		if(this.frm.doc.price_list_name) {
-			this.frm.call({
-				method: "setup.utils.get_price_list_currency",
-				args: {args: {
-					price_list_name: this.frm.doc.price_list_name,
-					use_for: "selling"
-				}},
-				callback: function(r) {
-					if(!r.exc) {
-						me.price_list_currency();
-					}
-				}
-			});
-		}
-	},
-	
-	currency: function() {
-		this.price_list_currency();
-	},
-	
-	price_list_currency: function() {
-		// What TODO? should we make price list system non-mandatory?
-		// this.frm.toggle_reqd("plc_conversion_rate",
-		// 	!!(this.frm.doc.price_list_name && this.frm.doc.price_list_currency));
-		
-		if(this.frm.doc.price_list_currency === this.get_company_currency()) {
-			this.frm.set_value("plc_conversion_rate", 1.0);
-			this.calculate_taxes_and_totals();
-		} else if(this.frm.doc.price_list_currency === this.frm.doc.currency) {
-			this.frm.set_value("plc_conversion_rate", this.frm.doc.conversion_rate);
-			this.calculate_taxes_and_totals();
-		}
-		
-		this.set_dynamic_labels();
-	},
-	
-	conversion_rate: function() {
-		this.price_list_currency();
-		this.calculate_taxes_and_totals();
-	},
-	
-	plc_conversion_rate: function() {
-		this.price_list_currency();
+		this._super("selling");
 	},
 	
 	ref_rate: function(doc, cdt, cdn) {
@@ -224,10 +126,6 @@
 		this.calculate_taxes_and_totals();
 	},
 	
-	qty: function(doc, cdt, cdn) {
-		this.calculate_taxes_and_totals();
-	},
-	
 	adj_rate: function(doc, cdt, cdn) {
 		this.ref_rate(doc, cdt, cdn);
 	},
@@ -246,19 +144,6 @@
 		this.calculate_taxes_and_totals();
 	},
 	
-	included_in_print_rate: function(doc, cdt, cdn) {
-		var tax = wn.model.get_doc(cdt, cdn);
-		try {
-			this.validate_on_previous_row(tax);
-			this.validate_inclusive_tax(tax);
-			this.calculate_taxes_and_totals();
-		} catch(e) {
-			tax.included_in_print_rate = 0;
-			refresh_field("included_in_print_rate", tax.name, tax.parentfield);
-			throw e;
-		}
-	},
-	
 	commission_rate: function() {
 		this.calculate_commission();
 		refresh_field("total_commission");
@@ -307,49 +192,10 @@
 		}
 	},
 	
-	validate_company_and_party: function() {
-		var me = this;
-		var valid = true;
-		$.each(["company", "customer"], function(i, fieldname) {
-			if(!me.frm.doc[fieldname]) {
-				valid = false;
-				msgprint(wn._("Please specify") + ": " + 
-					wn.meta.get_label(me.frm.doc.doctype, fieldname, me.frm.doc.name) + 
-					". " + wn._("It is needed to fetch Item Details."));
-			}
-		});
-		return valid;
-	},
-	
-	set_default_values: function() {
-		$.each(wn.model.get_doclist(this.frm.doctype, this.frm.docname), function(i, doc) {
-			var updated = wn.model.set_default_values(doc);
-			if(doc.parentfield) {
-				refresh_field(doc.parentfield);
-			} else {
-				refresh_field(updated);
-			}
-		});
-	},
-	
 	calculate_taxes_and_totals: function() {
-		this.frm.doc.conversion_rate = flt(this.frm.doc.conversion_rate, precision("conversion_rate"));
-		
-		// TODO 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.calculate_net_total();
-		this.calculate_taxes();
-		this.calculate_totals();
+		this._super();
 		this.calculate_commission();
 		this.calculate_contribution();
-		this._cleanup();
-		this.frm.doc.in_words = this.frm.doc.in_words_export = "";
 		
 		// TODO
 		// outstanding amount
@@ -357,57 +203,21 @@
 		// check for custom_recalc in custom scripts of server
 		
 		this.frm.refresh_fields();
-		this.show_item_wise_taxes();
-				
-	},
-	
-	get_item_doclist: function() {
-		return wn.model.get_doclist(this.frm.doc.doctype, this.frm.doc.name,
-			{parentfield: this.fname});
-	},
-	
-	get_tax_doclist: function() {
-		return wn.model.get_doclist(this.frm.doc.doctype, this.frm.doc.name,
-			{parentfield: "other_charges"});
 	},
 	
 	calculate_item_values: function() {
 		var me = this;
-		
-		var _set_base = function(item, print_field, base_field) {
-			// set values in base currency
-			item[base_field] = flt(item[print_field] * me.frm.doc.conversion_rate,
-				precision(base_field, item));
-		};
-		
 		$.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));
 			
-			_set_base(item, "ref_rate", "base_ref_rate");
-			_set_base(item, "export_rate", "basic_rate");
-			_set_base(item, "export_amount", "amount");
+			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");
 		});
 		
 	},
 	
-	initialize_taxes: function() {
-		var me = this;
-		$.each(this.frm.tax_doclist, function(i, tax) {
-			tax.tax_amount = tax.total = 0.0;
-			tax.item_wise_tax_detail = {};
-			
-			// temporary fields
-			tax.tax_amount_for_current_item = tax.grand_total_for_current_item = 0.0;
-			tax.tax_fraction_for_current_item = tax.grand_total_fraction_for_current_item = 0.0;
-			
-			me.validate_on_previous_row(tax);
-			me.validate_inclusive_tax(tax);
-			
-			wn.model.round_floats_in(tax);
-		});
-	},
-	
 	determine_exclusive_rate: function() {
 		var me = this;
 		$.each(me.frm.item_doclist, function(n, item) {
@@ -482,81 +292,6 @@
 		wn.model.round_floats_in(this.frm.doc, ["net_total", "net_total_export"]);
 	},
 	
-	calculate_taxes: function() {
-		var me = this;
-		
-		$.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);
-				
-				// 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;
-					}
-				
-				// 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;
-				
-				// Calculate tax.total viz. grand total till that step
-				// 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,
-						precision("total", tax));
-				} else {
-					tax.grand_total_for_current_item = 
-						flt(me.frm.tax_doclist[i-1].grand_total_for_current_item + current_tax_amount,
-							precision("total", tax));
-				}
-				
-				// in tax.total, accumulate grand total for each item
-				tax.total += tax.grand_total_for_current_item;
-				
-				// store tax breakup for each item
-				tax.item_wise_tax_detail[item.item_code || item.item_name] = current_tax_amount;
-				
-			});
-		});
-	},
-	
-	get_current_tax_amount: function(item, tax, item_tax_map) {
-		var tax_rate = this._get_tax_rate(tax, item_tax_map);
-		var current_tax_amount = 0.0;
-		
-		if(tax.charge_type == "Actual") {
-			// distribute the tax amount proportionally to each item row
-			var actual = flt(tax.rate, precision("tax_amount", tax));
-			current_tax_amount = this.frm.doc.net_total ?
-				((item.amount / this.frm.doc.net_total) * actual) :
-				0.0;
-			
-		} else if(tax.charge_type == "On Net Total") {
-			current_tax_amount = (tax_rate / 100.0) * item.amount;
-			
-		} else if(tax.charge_type == "On Previous Row Amount") {
-			current_tax_amount = (tax_rate / 100.0) *
-				this.frm.tax_doclist[cint(tax.row_id) - 1].tax_amount_for_current_item;
-			
-		} 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;
-			
-		}
-		
-		return flt(current_tax_amount, precision("tax_amount", tax));
-	},
-	
 	calculate_totals: function() {
 		var tax_count = this.frm.tax_doclist.length;
 		this.frm.doc.grand_total = flt(
@@ -601,91 +336,8 @@
 	},
 	
 	_cleanup: function() {
-		$.each(this.frm.tax_doclist, function(i, tax) {
-			var tax_fields = keys(tax);
-			$.each(["tax_amount_for_current_item", "grand_total_for_current_item",
-				"tax_fraction_for_current_item", "grand_total_fraction_for_current_item"], 
-				function(i, fieldname) { delete tax[fieldname];});
-			
-			tax.item_wise_tax_detail = JSON.stringify(tax.item_wise_tax_detail);
-		});
-	},
-	
-	validate_on_previous_row: function(tax) {
-		// validate if a valid row id is mentioned in case of
-		// On Previous Row Amount and On Previous Row Total
-		if((["On Previous Row Amount", "On Previous Row Total"].indexOf(tax.charge_type) != -1) &&
-			(!tax.row_id || cint(tax.row_id) >= tax.idx)) {
-				var msg = repl(wn._("Row") + " # %(idx)s [%(doctype)s]: " +
-					wn._("Please specify a valid") + " %(row_id_label)s", {
-						idx: tax.idx,
-						doctype: tax.doctype,
-						row_id_label: wn.meta.get_label(tax.doctype, "row_id", tax.name)
-					});
-				msgprint(msg);
-				throw msg;
-			}
-	},
-	
-	validate_inclusive_tax: function(tax) {
-		if(!this.frm.tax_doclist) this.frm.tax_doclist = this.get_tax_doclist();
-		
-		var actual_type_error = function() {
-			var msg = repl(wn._("For row") + " # %(idx)s [%(doctype)s]: " + 
-				"%(charge_type_label)s = \"%(charge_type)s\" " +
-				wn._("cannot be included in Item's rate"), {
-					idx: tax.idx,
-					doctype: tax.doctype,
-					charge_type_label: wn.meta.get_label(tax.doctype, "charge_type", tax.name),
-					charge_type: tax.charge_type
-				});
-			msgprint(msg);
-			throw msg;
-		};
-		
-		var on_previous_row_error = function(row_range) {
-			var msg = repl(wn._("For row") + " # %(idx)s [%(doctype)s]: " + 
-				wn._("to be included in Item's rate, it is required that: ") + 
-				" [" + wn._("Row") + " # %(row_range)s] " + wn._("also be included in Item's rate"), {
-					idx: tax.idx,
-					doctype: tax.doctype,
-					charge_type_label: wn.meta.get_label(tax.doctype, "charge_type", tax.name),
-					charge_type: tax.charge_type,
-					inclusive_label: wn.meta.get_label(tax.doctype, "included_in_print_rate", tax.name),
-					row_range: row_range,
-				});
-			
-			msgprint(msg);
-			throw msg;
-		};
-		
-		if(cint(tax.included_in_print_rate)) {
-			if(tax.charge_type == "Actual") {
-				// inclusive tax cannot be of type Actual
-				actual_type_error();
-			} else if(tax.charge_type == "On Previous Row Amount" &&
-				!cint(this.frm.tax_doclist[tax.row_id - 1].included_in_print_rate)) {
-					// referred row should also be an inclusive tax
-					on_previous_row_error(tax.row_id);
-			} else if(tax.charge_type == "On Previous Row Total") {
-				var taxes_not_included = $.map(this.frm.tax_doclist.slice(0, tax.row_id), 
-					function(t) { return cint(t.included_in_print_rate) ? null : t; });
-				if(taxes_not_included.length > 0) {
-					// all rows above this tax should be inclusive
-					on_previous_row_error(tax.row_id == 1 ? "1" : "1 - " + tax.row_id);
-				}
-			}
-		}
-	},
-	
-	_load_item_tax_rate: function(item_tax_rate) {
-		return item_tax_rate ? JSON.parse(item_tax_rate) : {};
-	},
-	
-	_get_tax_rate: function(tax, item_tax_map) {
-		return (keys(item_tax_map).indexOf(tax.account_head) != -1) ?
-			flt(item_tax_map[tax.account_head], precision("rate", tax)) :
-			tax.rate;
+		this._super();
+		this.frm.doc.in_words = this.frm.doc.in_words_export = "";
 	},
 
 	show_item_wise_taxes: function() {
@@ -693,40 +345,6 @@
 			.appendTo($(this.frm.fields_dict.other_charges_calculation.wrapper).empty());
 	},
 	
-	get_item_wise_taxes_html: function() {
-		var item_tax = {};
-		var tax_accounts = [];
-		var company_currency = this.get_company_currency();
-		
-		$.each(this.get_tax_doclist(), function(i, tax) {
-			var tax_amount_precision = precision("tax_amount", tax);
-			$.each(JSON.parse(tax.item_wise_tax_detail || '{}'), 
-				function(item_code, tax_amount) {
-					if(!item_tax[item_code]) item_tax[item_code] = {};
-					item_tax[item_code][tax.account_head] = flt(tax_amount, tax_amount_precision);
-				});
-			tax_accounts.push(tax.account_head);
-		});
-		
-		var headings = $.map([wn._("Item Name")].concat(tax_accounts), 
-			function(head) { return '<th style="min-width: 100px;">' + (head || "") + "</th>" }).join("\n");
-		
-		var rows = $.map(this.get_item_doclist(), function(item) {
-			var item_tax_record = item_tax[item.item_code || item.item_name];
-			return repl("<tr><td>%(item_name)s</td>%(taxes)s</tr>", {
-				item_name: item.item_name,
-				taxes: $.map(tax_accounts, function(head) {
-					return "<td>" + format_currency(item_tax_record[head], company_currency) + "</td>"
-				}).join("\n")
-			});
-		}).join("\n");
-		
-		return '<div style="overflow-x: scroll;"><table class="table table-bordered table-hover">\
-			<thead><tr>' + headings + '</tr></thead> \
-			<tbody>' + rows + '</tbody> \
-		</table></div>';
-	},
-	
 	get_charges: function() {
 		var me = this;
 		if(this.frm.doc.charge) {
@@ -837,9 +455,6 @@
 		});
 	},
 	
-	get_company_currency: function() {
-		return erpnext.get_currency(this.frm.doc.company);
-	}
 });
 
 // to save previous state of cur_frm.cscript
diff --git a/selling/doctype/sales_order/sales_order.js b/selling/doctype/sales_order/sales_order.js
index b792754..79f20bc 100644
--- a/selling/doctype/sales_order/sales_order.js
+++ b/selling/doctype/sales_order/sales_order.js
@@ -28,7 +28,7 @@
 
 
 cur_frm.cscript.onload = function(doc, cdt, cdn) {
-	cur_frm.cscript.manage_rounded_total();
+	cur_frm.cscript.toggle_rounded_total();
 	
 	if(!doc.status) set_multiple(cdt,cdn,{status:'Draft'});
 	if(!doc.transaction_date) set_multiple(cdt,cdn,{transaction_date:get_today()});
@@ -42,25 +42,10 @@
 	}
 }
 
-cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {
-	var callback = function(doc, cdt, cdn) {
-		if(doc.__islocal) {
-			// defined in sales_common.js
-			cur_frm.cscript.update_item_details(doc, cdt, cdn);
-		}
-	}
-	
-	cur_frm.cscript.hide_price_list_currency(doc, cdt, cdn, callback); 
-
-}
-
-
 cur_frm.cscript.refresh = function(doc, cdt, cdn) {
 	cur_frm.clear_custom_buttons();
 	erpnext.hide_naming_series();
 
-	if (!cur_frm.cscript.is_onload) cur_frm.cscript.hide_price_list_currency(doc, cdt, cdn); 
-	
 	cur_frm.toggle_display("contact_info", doc.customer);
 	
 	if(doc.docstatus==1) {
diff --git a/stock/doctype/delivery_note/delivery_note.js b/stock/doctype/delivery_note/delivery_note.js
index 0a31dfe..df5e761 100644
--- a/stock/doctype/delivery_note/delivery_note.js
+++ b/stock/doctype/delivery_note/delivery_note.js
@@ -43,15 +43,6 @@
 	}	
 }
 
-cur_frm.cscript.onload_post_render = function(doc, dt, dn) {
-	// defined in sales_common.js
-	var callback = function(doc, dt, dn) {
-		if(doc.__islocal) cur_frm.cscript.update_item_details(doc, dt, dn);
-	}
-
-	cur_frm.cscript.hide_price_list_currency(doc, dt, dn, callback); 
-} 
-
 // REFRESH
 // ================================================================================================
 cur_frm.cscript.refresh = function(doc, cdt, cdn) { 
diff --git a/stock/doctype/material_request/material_request.js b/stock/doctype/material_request/material_request.js
index 21bc141..3d4eed4 100644
--- a/stock/doctype/material_request/material_request.js
+++ b/stock/doctype/material_request/material_request.js
@@ -57,14 +57,6 @@
 $.extend(cur_frm.cscript, new_cscript);
 
 	
-cur_frm.cscript.onload = function(doc, cdt, cdn) {
-	if (!doc.transaction_date) doc.transaction_date = dateutil.obj_to_str(new Date());
-	if (!doc.status) doc.status = 'Draft';
-
-	// defined in purchase_common.js
-	//cur_frm.cscript.update_item_details(doc, cdt, cdn);
-};
-
 cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {
 	// second call
 	if(doc.__islocal){ 
@@ -79,12 +71,6 @@
 		}
 };
 
-cur_frm.cscript.transaction_date = function(doc,cdt,cdn){
-	if(doc.__islocal){ 
-		cur_frm.cscript.get_default_schedule_date(doc);
-	}
-};
-
 cur_frm.cscript.qty = function(doc, cdt, cdn) {
 	var d = locals[cdt][cdn];
 	if (flt(d.qty) < flt(d.min_order_qty))
diff --git a/stock/doctype/material_request/material_request.py b/stock/doctype/material_request/material_request.py
index 8a899b3..9f19a5b 100644
--- a/stock/doctype/material_request/material_request.py
+++ b/stock/doctype/material_request/material_request.py
@@ -17,9 +17,6 @@
 		self.tname = 'Material Request Item'
 		self.fname = 'indent_details'
 
-	def get_default_schedule_date(self):
-		get_obj(dt = 'Purchase Common').get_default_schedule_date(self)
-	
 	# get available qty at warehouse
 	def get_bin_details(self, arg = ''):
 		return get_obj(dt='Purchase Common').get_bin_details(arg)
@@ -30,22 +27,12 @@
 		self.check_if_already_pulled()
 		if self.doc.sales_order_no:
 			get_obj('DocType Mapper', 'Sales Order-Material Request', with_children=1).dt_map('Sales Order', 'Material Request', self.doc.sales_order_no, self.doc, self.doclist, "[['Sales Order', 'Material Request'],['Sales Order Item', 'Material Request Item']]")
-			self.get_item_defaults()
 		else:
 			msgprint("Please select Sales Order whose details need to pull")
 
 	def check_if_already_pulled(self):
 		pass#if self.[d.sales_order_no for d in getlist(self.doclist, 'indent_details')]
 
-
-	# Get item's other details
-	#- ------------------------
-	def get_item_defaults(self):
-		self.get_default_schedule_date()
-		for d in getlist(self.doclist, 'indent_details'):
-			det = webnotes.conn.sql("select min_order_qty from tabItem where name = '%s'" % d.item_code)
-			d.min_order_qty = det and flt(det[0][0]) or 0
-
 	# Validate so items
 	# ----------------------------
 	def validate_qty_against_so(self):
diff --git a/stock/doctype/purchase_receipt/purchase_receipt.js b/stock/doctype/purchase_receipt/purchase_receipt.js
index 82e494c..20740e7 100644
--- a/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -38,20 +38,6 @@
 			unhide_field(['challan_no', 'challan_date']);
 		}
 	}, 
-	onload_post_render: function(doc, dt, dn) {	
-		var me = this;
-		var callback = function(doc, dt, dn) {
-			me.update_item_details(doc, dt, dn, function(r,rt) { });
-		}
-		
-		// TODO: improve this
-		if(this.frm.doc.__islocal) {
-			if (this.frm.fields_dict.price_list_name && this.frm.doc.price_list_name) 
-				this.price_list_name(callback);
-			else
-				callback(doc, dt, dn);
-		}
-	}
 });
 
 var new_cscript = new erpnext.buying.PurchaseReceiptController({frm: cur_frm});