Merge branch 'master' of github.com:webnotes/erpnext
diff --git a/accounts/page/accounts_browser/accounts_browser.py b/accounts/page/accounts_browser/accounts_browser.py
index 76c64b7..8b24394 100644
--- a/accounts/page/accounts_browser/accounts_browser.py
+++ b/accounts/page/accounts_browser/accounts_browser.py
@@ -20,7 +20,7 @@
 	else:
 		return [r[0] for r in webnotes.conn.sql("""select name from tabCompany
 			where docstatus!=2""")]
-	
+
 @webnotes.whitelist()
 def get_children():
 	args = webnotes.form_dict
diff --git a/accounts/search_criteria/creditors_ledger/creditors_ledger.txt b/accounts/search_criteria/creditors_ledger/creditors_ledger.txt
index 9a7565c..12134e1 100644
--- a/accounts/search_criteria/creditors_ledger/creditors_ledger.txt
+++ b/accounts/search_criteria/creditors_ledger/creditors_ledger.txt
@@ -1,31 +1,27 @@
-# Search Criteria, creditors_ledger
 [
-
-	# These values are common in all dictionaries
-	{
-		'creation': '2012-04-03 12:49:51',
-		'docstatus': 0,
-		'modified': '2012-04-03 12:49:51',
-		'modified_by': u'Administrator',
-		'owner': u'nabin@webnotestech.com'
-	},
-
-	# These values are common for all Search Criteria
-	{
-		'criteria_name': u"Creditor's Ledger",
-		'doc_type': u'GL Entry',
-		'doctype': 'Search Criteria',
-		'filters': u"{'GL Entry\x01Voucher Type':'','GL Entry\x01Is Cancelled':'','GL Entry\x01Is Opening':'','GL Entry\x01Fiscal Year':''}",
-		'module': u'Accounts',
-		'name': '__common__',
-		'page_len': 50,
-		'sort_order': u'DESC',
-		'standard': u'Yes'
-	},
-
-	# Search Criteria, creditors_ledger
-	{
-		'doctype': 'Search Criteria',
-		'name': u'creditors_ledger'
-	}
+ {
+  "owner": "nabin@erpnext.com", 
+  "docstatus": 0, 
+  "creation": "2012-05-14 18:05:41", 
+  "modified_by": "nabin@erpnext.com", 
+  "modified": "2012-12-06 11:36:09"
+ }, 
+ {
+  "custom_query": null, 
+  "report_script": null, 
+  "page_len": 50, 
+  "module": "Accounts", 
+  "standard": "Yes", 
+  "sort_order": "DESC", 
+  "filters": "{\"GL Entry\\u0001Voucher Type\":[],\"GL Entry\\u0001Is Cancelled\":[\"No\"],\"GL Entry\\u0001Is Opening\":[\"\"],\"GL Entry\\u0001Fiscal Year\":[\"\"]}", 
+  "doc_type": "GL Entry", 
+  "name": "__common__", 
+  "doctype": "Search Criteria", 
+  "sort_by": "`tabGL Entry`.`name`", 
+  "criteria_name": "Creditor's Ledger"
+ }, 
+ {
+  "name": "creditors_ledger", 
+  "doctype": "Search Criteria"
+ }
 ]
\ No newline at end of file
diff --git a/accounts/search_criteria/debtors_ledger/debtors_ledger.txt b/accounts/search_criteria/debtors_ledger/debtors_ledger.txt
index 0991097..a868003 100644
--- a/accounts/search_criteria/debtors_ledger/debtors_ledger.txt
+++ b/accounts/search_criteria/debtors_ledger/debtors_ledger.txt
@@ -1,31 +1,27 @@
-# Search Criteria, debtors_ledger
 [
-
-	# These values are common in all dictionaries
-	{
-		'creation': '2012-04-03 12:49:51',
-		'docstatus': 0,
-		'modified': '2012-04-03 12:49:51',
-		'modified_by': u'Administrator',
-		'owner': u'nabin@webnotestech.com'
-	},
-
-	# These values are common for all Search Criteria
-	{
-		'criteria_name': u"Debtor's Ledger",
-		'doc_type': u'GL Entry',
-		'doctype': 'Search Criteria',
-		'filters': u"{'GL Entry\x01Voucher Type':'','GL Entry\x01Is Cancelled':'No','GL Entry\x01Is Opening':'','GL Entry\x01Fiscal Year':''}",
-		'module': u'Accounts',
-		'name': '__common__',
-		'page_len': 50,
-		'sort_order': u'DESC',
-		'standard': u'Yes'
-	},
-
-	# Search Criteria, debtors_ledger
-	{
-		'doctype': 'Search Criteria',
-		'name': u'debtors_ledger'
-	}
+ {
+  "owner": "nabin@erpnext.com", 
+  "docstatus": 0, 
+  "creation": "2012-05-14 18:05:42", 
+  "modified_by": "nabin@erpnext.com", 
+  "modified": "2012-12-06 11:37:15"
+ }, 
+ {
+  "custom_query": null, 
+  "report_script": null, 
+  "page_len": 50, 
+  "module": "Accounts", 
+  "standard": "Yes", 
+  "sort_order": "DESC", 
+  "filters": "{\"GL Entry\\u0001Voucher Type\":[],\"GL Entry\\u0001Is Cancelled\":[\"No\"],\"GL Entry\\u0001Is Opening\":[],\"GL Entry\\u0001Fiscal Year\":[]}", 
+  "doc_type": "GL Entry", 
+  "name": "__common__", 
+  "doctype": "Search Criteria", 
+  "sort_by": "`tabGL Entry`.`name`", 
+  "criteria_name": "Debtor's Ledger"
+ }, 
+ {
+  "name": "debtors_ledger", 
+  "doctype": "Search Criteria"
+ }
 ]
\ No newline at end of file
diff --git a/buying/doctype/purchase_common/purchase_common.js b/buying/doctype/purchase_common/purchase_common.js
index 3b72236..b29ccb7 100644
--- a/buying/doctype/purchase_common/purchase_common.js
+++ b/buying/doctype/purchase_common/purchase_common.js
@@ -199,23 +199,35 @@
 }
 
 //==================== UOM ======================================================================
-cur_frm.cscript.uom = function(doc, cdt, cdn) {
+cur_frm.cscript.uom = function(doc, cdt, cdn, args) {
+	if(!args) args = {};
+	
+	// args passed can contain conversion_factor
 	var d = locals[cdt][cdn];
-	if (d.item_code && d.uom) {
-		call_back = function(doc, cdt, cdn){
-			cur_frm.cscript.calc_amount(doc, 2);
-		}
-		str_arg = {'item_code':d.item_code, 'uom':d.uom, 'stock_qty':flt(d.stock_qty), 'qty': flt(d.qty), 'conversion_rate':doc.conversion_rate, 'doc_name': doc.name}
-		// Updates Conversion Factor, Qty and Purchase Rate
-		get_server_fields('get_uom_details',JSON.stringify(str_arg), fname, doc,cdt,cdn,1, call_back);
-		// don't make mistake of calling update_stock_qty() the get_uom_details returns stock_qty as per conversion factor properly
+	$.extend(args, {
+		item_code: d.item_code,
+		uom: d.uom,
+		stock_qty: flt(d.stock_qty),
+	});
+	
+	if(d.item_code && d.uom) {
+		cur_frm.call({
+			method: "buying.doctype.purchase_common.purchase_common.get_uom_details",
+			args: { args: args },
+			child: d,
+			callback: function(r) {
+				cur_frm.cscript.calc_amount(doc, 2);
+			}
+		});
 	}
 }
 
 
 //==================== Conversion factor =========================================================
 cur_frm.cscript.conversion_factor = function(doc, cdt, cdn) {
-	cur_frm.cscript.uom(doc, cdt, cdn);
+	var item = locals[cdt][cdn];
+	
+	cur_frm.cscript.uom(doc, cdt, cdn, { conversion_factor: item.conversion_factor });
 }
 
 //==================== stock qty ======================================================================
diff --git a/buying/doctype/purchase_common/purchase_common.py b/buying/doctype/purchase_common/purchase_common.py
index eb8ebef..9c1187d 100644
--- a/buying/doctype/purchase_common/purchase_common.py
+++ b/buying/doctype/purchase_common/purchase_common.py
@@ -182,39 +182,6 @@
 		ret = { 'projected_qty' : bin and flt(bin[0]['projected_qty']) or 0 }
 		return ret
 
-	def get_uom_details(self, arg = ''):
-		"""fetches details on change of UOM"""
-		import json
-		arg, ret = json.loads(arg), {}
-	
-		uom = webnotes.conn.sql("""\
-			select conversion_factor
-			from `tabUOM Conversion Detail`
-			where parent = %s and uom = %s""", (arg['item_code'],arg['uom']), as_dict = 1)
-		
-		if not uom: return ret
-		
-		last_purchase_details, last_purchase_date = self.get_last_purchase_details(arg['item_code'], arg['doc_name'])
-
-		conversion_factor = flt(uom[0]['conversion_factor'])
-		conversion_rate = flt(arg['conversion_rate'])
-		purchase_ref_rate = last_purchase_details and \
-							(last_purchase_details['purchase_ref_rate'] * conversion_factor) or 0
-		purchase_rate = last_purchase_details and \
-						(last_purchase_details['purchase_rate'] * conversion_factor) or 0
-
-		ret = {
-			'conversion_factor': conversion_factor,
-			'qty': flt(arg['stock_qty']) / conversion_factor,
-			'purchase_ref_rate': purchase_ref_rate,
-			'purchase_rate': purchase_rate,
-			'import_ref_rate': purchase_ref_rate / conversion_rate,
-			'import_rate': purchase_rate / conversion_rate,
-		}
-		
-		return ret
-	
-		
 	# --- Last Purchase Rate related methods ---
 	
 	def update_last_purchase_rate(self, obj, is_submit):
@@ -683,3 +650,27 @@
 			if d.prevdoc_doctype and d.prevdoc_docname:
 				dt = sql("select transaction_date from `tab%s` where name = '%s'" % (d.prevdoc_doctype, d.prevdoc_docname))
 				d.prevdoc_date = dt and dt[0][0].strftime('%Y-%m-%d') or ''
+
+@webnotes.whitelist()
+def get_uom_details(args=None):
+	"""fetches details on change of UOM"""
+	if not args:
+		return {}
+		
+	if isinstance(args, basestring):
+		import json
+		args = json.loads(args)
+
+	uom = webnotes.conn.sql("""select conversion_factor
+		from `tabUOM Conversion Detail` where parent = %s and uom = %s""", 
+		(args['item_code'], args['uom']), as_dict=1)
+
+	if not uom: return {}
+
+	conversion_factor = args.get("conversion_factor") or \
+		flt(uom[0]["conversion_factor"])
+	
+	return {
+		"conversion_factor": conversion_factor,
+		"qty": flt(args["stock_qty"]) / conversion_factor,
+	}
\ No newline at end of file
diff --git a/buying/doctype/purchase_order/purchase_order.py b/buying/doctype/purchase_order/purchase_order.py
index 4497bcd..e52499c 100644
--- a/buying/doctype/purchase_order/purchase_order.py
+++ b/buying/doctype/purchase_order/purchase_order.py
@@ -69,10 +69,6 @@
 
 
 
-	# Get UOM Details
-	def get_uom_details(self, arg = ''):
-		return get_obj('Purchase Common').get_uom_details(arg)
-
 	# get available qty at warehouse
 	def get_bin_details(self, arg = ''):
 		return get_obj(dt='Purchase Common').get_bin_details(arg)
diff --git a/buying/doctype/purchase_order/purchase_order_list.js b/buying/doctype/purchase_order/purchase_order_list.js
index 69f97f5..762c635 100644
--- a/buying/doctype/purchase_order/purchase_order_list.js
+++ b/buying/doctype/purchase_order/purchase_order_list.js
@@ -27,7 +27,7 @@
 			},
 			css: {'text-align':'right'}
 		},
-		{width: '8%', content: 'per_received', type:'bar-graph', label:'Delivered'},
+		{width: '8%', content: 'per_received', type:'bar-graph', label:'Received'},
 		{width: '8%', content: 'per_billed', type:'bar-graph', label:'Billed'},
 		{width: '12%', content:'transaction_date',
 			css: {'text-align': 'right', 'color':'#777'},
diff --git a/buying/doctype/purchase_request/purchase_request.py b/buying/doctype/purchase_request/purchase_request.py
index 79c7400..7d0e08e 100644
--- a/buying/doctype/purchase_request/purchase_request.py
+++ b/buying/doctype/purchase_request/purchase_request.py
@@ -121,11 +121,6 @@
 							doc.fields[r] = ret[r]
 
 
-	# Get UOM Details
-	# ---------------------------------
-	def get_uom_details(self, arg = ''):
-		return get_obj(dt='Purchase Common').get_uom_details(arg)
-
 	# GET TERMS & CONDITIONS
 	#-----------------------------
 	def get_tc_details(self):
@@ -219,4 +214,4 @@
 		self.update_bin(is_submit = 0, is_stopped = (cstr(self.doc.status) == 'Stopped') and 1 or 0)
 		
 		# Step 5:=> Set Status
-		webnotes.conn.set(self.doc,'status','Cancelled')
+		webnotes.conn.set(self.doc,'status','Cancelled')
\ No newline at end of file
diff --git a/controllers/tax_controller.py b/controllers/tax_controller.py
index 7aa8e23..d70ba3e 100644
--- a/controllers/tax_controller.py
+++ b/controllers/tax_controller.py
@@ -140,7 +140,7 @@
 		self.doc.net_total = flt(self.doc.net_total, self.precision.main.net_total)
 		self.doc.fields[self.fmap.net_total_print] = \
 			flt(self.doc.fields.get(self.fmap.net_total_print),
-			self.precision.main[self.fmap.net_total_print])
+			self.precision.main.get(self.fmap.net_total_print))
 			
 	def calculate_taxes(self):
 		for item in self.item_doclist:
diff --git a/home/page/latest_updates/latest_updates.js b/home/page/latest_updates/latest_updates.js
index 09befee..d3bde12 100644
--- a/home/page/latest_updates/latest_updates.js
+++ b/home/page/latest_updates/latest_updates.js
@@ -1,5 +1,7 @@
 erpnext.updates = [
 	["5th December 2012", [
+		"Leave Application: Now can set approver.",
+		"New Roles Added: Leave Approver and Expense Approver.",
 		"Production Order is now linked with sales order.",
 		"Production Planning Tool: The field 'Allow SA items as raw material' has been renamed to 'Use multi-level BOM', 'Include in plan' column from SO table has been deleted",
 		"Batch nos are now filtered with item and available qty",
diff --git a/hr/__init__.py b/hr/__init__.py
index 96bd47b..429c719 100644
--- a/hr/__init__.py
+++ b/hr/__init__.py
@@ -3,4 +3,6 @@
 	{"doctype":"Role", "role_name":"Employee", "name":"Employee"},
 	{"doctype":"Role", "role_name":"HR Manager", "name":"HR Manager"},
 	{"doctype":"Role", "role_name":"HR User", "name":"HR User"},
+	{"doctype":"Role", "role_name":"Leave Approver", "name":"Leave Approver"},
+	{"doctype":"Role", "role_name":"Expense Approver", "name":"Expense Approver"},
 ]
diff --git a/hr/doctype/expense_claim/expense_claim.js b/hr/doctype/expense_claim/expense_claim.js
index 466a8cf..8ba0978 100644
--- a/hr/doctype/expense_claim/expense_claim.js
+++ b/hr/doctype/expense_claim/expense_claim.js
@@ -15,79 +15,84 @@
 // along with this program.	If not, see <http://www.gnu.org/licenses/>.
 
 cur_frm.add_fetch('employee', 'company', 'company');
+cur_frm.add_fetch('employee','employee_name','employee_name');
 
 cur_frm.cscript.onload = function(doc,cdt,cdn){
-	// 
-	if(!doc.approval_status) set_multiple(cdt,cdn,{approval_status:'Draft'});
-	if(doc.employee) cur_frm.cscript.employee(doc,cdt,cdn);
-	
+	if(!doc.approval_status)
+		cur_frm.set_value("approval_status", "Draft")
+			
 	if (doc.__islocal) {
-		if(doc.amended_from) set_multiple(cdt,cdn,{approval_status:'Draft'});
-		var val = getchildren('Expense Claim Detail', doc.name, 'expense_voucher_details', doc.doctype);
-		for(var i = 0; i<val.length; i++){
-			val[i].sanctioned_amount ='';
-		}
-		doc.total_sanctioned_amount = '';
-		refresh_many(['sanctioned_amount', 'total_sanctioned_amount']);
+		cur_frm.set_value("posting_date", dateutil.get_today());
+		if(doc.amended_from) 
+			cur_frm.set_value("approval_status", "Draft");
+		cur_frm.cscript.clear_sanctioned(doc);
 	}
+
+	cur_frm.call({
+		method:"get_approver_list",
+		callback: function(r) {
+			cur_frm.set_df_property("exp_approver", "options", r.message);
+		}
+	});	
+}
+
+cur_frm.cscript.clear_sanctioned = function(doc) {
+	var val = getchildren('Expense Claim Detail', doc.name, 
+		'expense_voucher_details', doc.doctype);
+	for(var i = 0; i<val.length; i++){
+		val[i].sanctioned_amount ='';
+	}
+
+	doc.total_sanctioned_amount = '';
+	refresh_many(['sanctioned_amount', 'total_sanctioned_amount']);	
 }
 
 cur_frm.cscript.refresh = function(doc,cdt,cdn){
-	hide_field('calculate_total_amount');
-	if(user == doc.exp_approver && doc.approval_status == 'Submitted'){
-		unhide_field(['update_voucher', 'approve', 'reject', 'calculate_total_amount']);
-		cur_frm.fields_dict['expense_voucher_details'].grid.set_column_disp('sanctioned_amount', true);
-		set_field_permlevel('remark', 0);
+	cur_frm.set_intro("");
+	if(doc.__islocal && !in_list(user_roles, "HR User")) {
+		cur_frm.set_intro("Fill the form and save it")
 	} else {
-		hide_field(['update_voucher', 'approve', 'reject']);
-		cur_frm.fields_dict['expense_voucher_details'].grid.set_column_disp('sanctioned_amount', false);
-		set_field_permlevel('remark', 1);
+		if(doc.approval_status=="Draft") {		
+			if(user==doc.exp_approver) {
+				if(doc.approval_status=="Draft") {
+					cur_frm.set_intro("You are the Expense Approver for this record. Please Update the 'Status' and Save");
+					cur_frm.toggle_enable("approval_status", true);
+				}
+			} else {
+				cur_frm.set_intro("Expense Claim is pending approval. Only the Expense Approver can update status.");
+				cur_frm.toggle_enable("approval_status", false);
+			}
+		} else {
+			if(doc.approval_status=="Approved") {
+				cur_frm.set_intro("Expense Claim has been approved.");
+			} else if(doc.approval_status=="Rejected") {
+				cur_frm.set_intro("Expense Claim has been rejected.");
+			}
+		}
 	}
-	if (doc.docstatus == 0) unhide_field('calculate_total_amount');
-}
+	
+	if(doc.approval_status=="Approved" && doc.docstatus==0) {
+		cur_frm.savesubmit()
+	}}
 
 cur_frm.cscript.validate = function(doc) {
-	if(cint(doc.docstatus) == 0) {
-		doc.approval_status = "Draft";
-	}
 	cur_frm.cscript.calculate_total(doc);
 }
 
-cur_frm.cscript.employee = function(doc,cdt,cdn){
-	if(doc.employee){
-		$c_obj(make_doclist(doc.doctype, doc.name),'set_approver','', function(r,rt){
-			if(r.message){
-				doc.employee_name = r.message['emp_nm'];
-				wn.meta.get_docfield(doc.doctype, 'exp_approver' , doc.name).options = r.message['app_lst'];				
-				refresh_many(['exp_approver','employee_name']);
-			}		
-		});
-	}
-}
-
 cur_frm.cscript.calculate_total = function(doc,cdt,cdn){
-	if(doc.approval_status == 'Draft'){
-		var val = getchildren('Expense Claim Detail', doc.name, 'expense_voucher_details', doc.doctype);
-		var total_claim =0;
-		for(var i = 0; i<val.length; i++){
-			val[i].sanctioned_amount = val[i].claim_amount;
-			total_claim = flt(total_claim)+flt(val[i].claim_amount);
-			refresh_field('sactioned_amount', val[i].name, 'expense_voucher_details'); 
+	doc.total_claimed_amount = 0;
+	doc.total_sanctioned_amount = 0;
+	$.each(wn.model.get("Expense Claim Detail", {parent:doc.name}), function(i, d) {
+		doc.total_claimed_amount += d.claim_amount;
+		if(d.sanctioned_amount==null) {
+			d.sanctioned_amount = d.claim_amount;
 		}
-		doc.total_claimed_amount = flt(total_claim);
-		refresh_field('total_claimed_amount');
-	}
-	else if(doc.approval_status == 'Submitted'){
-		var val = getchildren('Expense Claim Detail', doc.name, 'expense_voucher_details', doc.doctype);
-		var total_sanctioned = 0;
-		for(var i = 0; i<val.length; i++){
-			total_sanctioned = flt(total_sanctioned)+flt(val[i].sanctioned_amount);
-			refresh_field('sactioned_amount', val[i].name, 'expense_voucher_details'); 
-			
-		}
-		doc.total_sanctioned_amount = flt(total_sanctioned);
-		refresh_field('total_sanctioned_amount');
-	}
+		doc.total_sanctioned_amount += d.sanctioned_amount;
+	});
+	
+	refresh_field("total_claimed_amount");
+	refresh_field('total_sanctioned_amount');
+
 }
 
 cur_frm.cscript.calculate_total_amount = function(doc,cdt,cdn){
@@ -100,155 +105,8 @@
 	cur_frm.cscript.calculate_total(doc,cdt,cdn);
 }
 
-cur_frm.cscript.approve = function(doc,cdt,cdn){
-	cur_frm.cscript.calculate_total(doc,cdt,cdn);
-
-	if(user == doc.exp_approver){
-		var approve_voucher_dialog;
-		
-		set_approve_voucher_dialog = function() {
-			approve_voucher_dialog = new Dialog(400, 200, 'Approve Voucher');
-			approve_voucher_dialog.make_body([
-				['HTML', 'Message', '<div class = "comment">You wont be able to do any changes after approving this expense voucher. Are you sure, you want to approve it ?</div>'],
-				['HTML', 'Response', '<div class = "comment" id="approve_voucher_dialog_response"></div>'],
-				['HTML', 'Approve Voucher', '<div></div>']
-			]);
-			
-			var approve_voucher_btn1 = $a($i(approve_voucher_dialog.widgets['Approve Voucher']), 'button', 'button');
-			approve_voucher_btn1.innerHTML = 'Yes';
-			approve_voucher_btn1.onclick = function(){ approve_voucher_dialog.add(); }
-			
-			var approve_voucher_btn2 = $a($i(approve_voucher_dialog.widgets['Approve Voucher']), 'button', 'button');
-			approve_voucher_btn2.innerHTML = 'No';
-			$y(approve_voucher_btn2,{marginLeft:'4px'});
-			approve_voucher_btn2.onclick = function(){ approve_voucher_dialog.hide();}
-			
-			approve_voucher_dialog.onshow = function() {
-				$i('approve_voucher_dialog_response').innerHTML = '';
-			}
-			
-			approve_voucher_dialog.add = function() {
-				// sending...
-				$i('approve_voucher_dialog_response').innerHTML = 'Processing...';
-				
-				$c_obj(make_doclist(this.doc.doctype, this.doc.name),'approve_voucher','', function(r,rt){
-					if(r.message == 'Approved'){
-						$i('approve_voucher_dialog_response').innerHTML = 'Approved';
-						refresh_field('approval_status');
-						hide_field(['update_voucher', 'approve', 'reject', 'calculate_total_amount']);
-						approve_voucher_dialog.hide();
-			var args = {
-				type: 'Expense Claim Approved',
-				doctype: 'Expense Claim',
-				contact_name: doc.employee_name,
-				send_to: doc.email_id
-			}
-			cur_frm.cscript.notify(doc, args);
-					}
-					else if(r.message == 'Incomplete'){
-						$i('approve_voucher_dialog_response').innerHTML = 'Incomplete Voucher';
-					}
-					else if(r.message == 'No Amount'){
-						$i('approve_voucher_dialog_response').innerHTML = 'Calculate total amount';
-					}
-				});
-			}
-		}	
-		
-		if(!approve_voucher_dialog){
-			set_approve_voucher_dialog();
-		}	
-		approve_voucher_dialog.doc = doc;
-		approve_voucher_dialog.cdt = cdt;
-		approve_voucher_dialog.cdn = cdn;
-		approve_voucher_dialog.show();
-		refresh_field('expense_voucher_details');
-		doc.__unsaved = 0;
-		cur_frm.refresh_header();
-	}else{
-		msgprint("Expense Claim can be approved by Approver only");
-	}
-}
-
-cur_frm.cscript.reject = function(doc,cdt,cdn){
-	cur_frm.cscript.calculate_total(doc,cdt,cdn);
-	
-	if(user == doc.exp_approver){
-		var reject_voucher_dialog;
-		
-		set_reject_voucher_dialog = function() {
-			reject_voucher_dialog = new Dialog(400, 200, 'Reject Voucher');
-			reject_voucher_dialog.make_body([
-				['HTML', 'Message', '<div class = "comment">You wont be able to do any changes after rejecting this expense voucher. Are you sure, you want to reject it ?</div>'],
-				['HTML', 'Response', '<div class = "comment" id="reject_voucher_dialog_response"></div>'],
-				['HTML', 'Reject Voucher', '<div></div>']
-			]);
-			
-			var reject_voucher_btn1 = $a($i(reject_voucher_dialog.widgets['Reject Voucher']), 'button', 'button');
-			reject_voucher_btn1.innerHTML = 'Yes';
-			reject_voucher_btn1.onclick = function(){ reject_voucher_dialog.add(); }
-			
-			var reject_voucher_btn2 = $a($i(reject_voucher_dialog.widgets['Reject Voucher']), 'button', 'button');
-			reject_voucher_btn2.innerHTML = 'No';
-			$y(reject_voucher_btn2,{marginLeft:'4px'});
-			reject_voucher_btn2.onclick = function(){ reject_voucher_dialog.hide();}
-			
-			reject_voucher_dialog.onshow = function() {
-				$i('reject_voucher_dialog_response').innerHTML = '';
-			}
-			
-			reject_voucher_dialog.add = function() {
-				// sending...
-				$i('reject_voucher_dialog_response').innerHTML = 'Processing...';
-				
-				$c_obj(make_doclist(this.doc.doctype, this.doc.name),'reject_voucher','', function(r,rt){
-					if(r.message == 'Rejected'){
-						$i('reject_voucher_dialog_response').innerHTML = 'Rejected';
-						refresh_field('approval_status');
-						hide_field(['update_voucher', 'approve', 'reject', 'calculate_total_amount']);
-						reject_voucher_dialog.hide();
-			var args = {
-				type: 'Expense Claim Rejected',
-				doctype: 'Expense Claim',
-				contact_name: doc.employee_name,
-				send_to: doc.email_id
-			}
-			cur_frm.cscript.notify(doc, args);
-					}
-				});
-			}
-		}	
-		
-		if(!reject_voucher_dialog){
-			set_reject_voucher_dialog();
-		}	
-		reject_voucher_dialog.doc = doc;
-		reject_voucher_dialog.cdt = cdt;
-		reject_voucher_dialog.cdn = cdn;
-		reject_voucher_dialog.show();
-		refresh_field('expense_voucher_details');
-		doc.__unsaved = 0;
-		cur_frm.refresh_header();
-	}else{
-		msgprint("Expense Claim can be rejected by Approver only");
-	}
-}
-
-//update follow up
-//=================================================================================
-cur_frm.cscript.update_voucher = function(doc){
-
-	$c_obj(make_doclist(doc.doctype, doc.name),'update_voucher','',function(r, rt){
-		refresh_field('expense_voucher_details');
-		doc.__unsaved = 0;
-		cur_frm.refresh_header();
-	});
-}
-
 cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
-	if(cint(wn.boot.notification_settings.expense_claim)) {
+	if(cint(wn.boot.notification_settings && wn.boot.notification_settings.expense_claim)) {
 		cur_frm.email_doc(wn.boot.notification_settings.expense_claim_message);
 	}
-}
-
-cur_frm.fields_dict.employee.get_query = erpnext.utils.employee_query;
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/hr/doctype/expense_claim/expense_claim.py b/hr/doctype/expense_claim/expense_claim.py
index 0bfc318..b5fddda 100644
--- a/hr/doctype/expense_claim/expense_claim.py
+++ b/hr/doctype/expense_claim/expense_claim.py
@@ -17,86 +17,27 @@
 from __future__ import unicode_literals
 import webnotes
 
-from webnotes.utils import add_days, cstr
-from webnotes.model import db_exists
-from webnotes.model.wrapper import getlist, copy_doclist
-from webnotes.model.code import get_obj
+from webnotes.utils import add_days
+from webnotes.model.wrapper import getlist
 from webnotes import form, msgprint
 
 sql = webnotes.conn.sql
-	
-
 
 class DocType:
 	def __init__(self, doc, doclist=[]):
 		self.doc = doc
 		self.doclist = doclist
 
-	def get_employee_name(self):
-		emp_dtl = sql("select employee_name,company_email from `tabEmployee` where name=%s", self.doc.employee)
-		emp_nm = emp_dtl and emp_dtl[0][0] or ''
-		self.doc.employee_name = emp_nm
-		self.doc.email_id = emp_dtl and emp_dtl[0][1] or ''
-
-		return cstr(emp_nm)	
-	
-	def get_approver_lst(self):
-		approver_lst =[]
-		approver_lst1 = get_obj('Authorization Control').get_approver_name(self.doc.doctype,0,self)
-		if approver_lst1:
-			approver_lst=approver_lst1
-		else:
-			approver_lst = [x[0] for x in sql("select distinct name from `tabProfile` where enabled=1 and name!='Administrator' and name!='Guest' and docstatus!=2")]
-		return approver_lst
-
-	def set_approver(self):
-		ret={}
-		approver_lst =[]
-		emp_nm = self.get_employee_name()
-		approver_lst = self.get_approver_lst()		
-		ret = {'app_lst':"\n" + "\n".join(approver_lst), 'emp_nm':cstr(emp_nm)}
-		return ret
-
-	def update_voucher(self):
-		sql("delete from `tabExpense Claim Detail` where parent = '%s'"%self.doc.name)
-		for d in getlist(self.doclist, 'expense_voucher_details'):
-			if not d.expense_type or not d.claim_amount:
-				msgprint("Please remove the extra blank row added")
-				raise Exception
-			d.save(1)
-		if self.doc.total_sanctioned_amount:
-			webnotes.conn.set(self.doc,'total_sanctioned_amount',self.doc.total_sanctioned_amount)
-		if self.doc.remark:
-			webnotes.conn.set(self.doc, 'remark', self.doc.remark)
-	
-	def approve_voucher(self):
-		missing_count = 0
-		for d in getlist(self.doclist, 'expense_voucher_details'):
-			if not d.sanctioned_amount:
-				missing_count += 1
-		if missing_count == len(getlist(self.doclist, 'expense_voucher_details')):
-			msgprint("Please add 'Sanctioned Amount' for atleast one expense")
-			return cstr('Incomplete')
-		
-		if not self.doc.total_sanctioned_amount:
-			msgprint("Please calculate total sanctioned amount using button 'Calculate Total Amount'")
-			return cstr('No Amount')
-		self.update_voucher()
-		
-		webnotes.conn.set(self.doc, 'approval_status', 'Approved')		
-		# on approval notification
-		#get_obj('Notification Control').notify_contact('Expense Claim Approved', self.doc.doctype, self.doc.name, self.doc.email_id, self.doc.employee_name)
-
-		return cstr('Approved')
-	
-	def reject_voucher(self):
-		
-		if self.doc.remark:
-			webnotes.conn.set(self.doc, 'remark', self.doc.remark)	 
-		webnotes.conn.set(self.doc, 'approval_status', 'Rejected')		
-
-		return cstr('Rejected')
-	
+	def validate(self):
+		if self.doc.exp_approver == self.doc.owner:
+			webnotes.msgprint("""Self Approval is not allowed.""", raise_exception=1)
+		self.validate_fiscal_year()
+		self.validate_exp_details()
+			
+	def on_submit(self):
+		if self.doc.approval_status=="Draft":
+			webnotes.msgprint("""Please set Approval Status to 'Approved' or 'Rejected' before submitting""",
+				raise_exception=1)
 	
 	def validate_fiscal_year(self):
 		fy=sql("select year_start_date from `tabFiscal Year` where name='%s'"%self.doc.fiscal_year)
@@ -105,33 +46,16 @@
 		if str(self.doc.posting_date) < str(ysd) or str(self.doc.posting_date) > str(yed):
 			msgprint("Posting Date is not within the Fiscal Year selected")
 			raise Exception
-		
-	def validate(self):
-		self.validate_fiscal_year()
-		
-	def on_update(self):
-		webnotes.conn.set(self.doc, 'approval_status', 'Draft')
-	
+			
 	def validate_exp_details(self):
 		if not getlist(self.doclist, 'expense_voucher_details'):
 			msgprint("Please add expense voucher details")
 			raise Exception
 		
-		if not self.doc.total_claimed_amount:
-			msgprint("Please calculate Total Claimed Amount")
-			raise Exception
-		
-		if not self.doc.exp_approver:
-			msgprint("Please select Expense Claim approver")
-			raise Exception
-		
-	def on_submit(self):
-		self.validate_exp_details()
-		webnotes.conn.set(self.doc, 'approval_status', 'Submitted')
-	
-	def on_cancel(self):
-		webnotes.conn.set(self.doc, 'approval_status', 'Cancelled')
-
-	def get_formatted_message(self, args):
-		""" get formatted message for auto notification"""
-		return get_obj('Notification Control').get_formatted_message(args)
+@webnotes.whitelist()
+def get_approver_list():
+	roles = [r[0] for r in webnotes.conn.sql("""select distinct parent from `tabUserRole`
+		where role='Expense Approver'""")]
+	if not roles:
+		webnotes.msgprint("No Expense Approvers. Please assign 'Expense Approver' Role to atleast one user.")
+	return roles
diff --git a/hr/doctype/expense_claim/expense_claim.txt b/hr/doctype/expense_claim/expense_claim.txt
index 34ed31c..f42e2dd 100644
--- a/hr/doctype/expense_claim/expense_claim.txt
+++ b/hr/doctype/expense_claim/expense_claim.txt
@@ -1,390 +1,271 @@
-# DocType, Expense Claim
 [
-
-	# These values are common in all dictionaries
-	{
-		'creation': '2012-03-27 14:35:56',
-		'docstatus': 0,
-		'modified': '2012-03-27 14:45:48',
-		'modified_by': u'Administrator',
-		'owner': u'harshada@webnotestech.com'
-	},
-
-	# These values are common for all DocType
-	{
-		'_last_update': u'1308808105',
-		'autoname': u'EXP.######',
-		'colour': u'White:FFF',
-		'default_print_format': u'Standard',
-		'doctype': 'DocType',
-		'is_submittable': 1,
-		'module': u'HR',
-		'name': '__common__',
-		'search_fields': u'approval_status,employee,employee_name',
-		'section_style': u'Simple',
-		'server_code_error': u' ',
-		'show_in_menu': 0,
-		'subject': u'From %(employee_name)s for %(total_claimed_amount)s (claimed)',
-		'tag_fields': u'approval_status',
-		'version': 135
-	},
-
-	# These values are common for all DocField
-	{
-		'doctype': u'DocField',
-		'name': '__common__',
-		'parent': u'Expense Claim',
-		'parentfield': u'fields',
-		'parenttype': u'DocType'
-	},
-
-	# These values are common for all DocPerm
-	{
-		'doctype': u'DocPerm',
-		'name': '__common__',
-		'parent': u'Expense Claim',
-		'parentfield': u'permissions',
-		'parenttype': u'DocType',
-		'read': 1
-	},
-
-	# DocType, Expense Claim
-	{
-		'doctype': 'DocType',
-		'name': u'Expense Claim'
-	},
-
-	# DocPerm
-	{
-		'doctype': u'DocPerm',
-		'permlevel': 1,
-		'role': u'All'
-	},
-
-	# DocPerm
-	{
-		'amend': 1,
-		'cancel': 1,
-		'create': 1,
-		'doctype': u'DocPerm',
-		'match': u'owner',
-		'permlevel': 0,
-		'submit': 1,
-		'write': 1
-	},
-
-	# DocPerm
-	{
-		'amend': 1,
-		'cancel': 1,
-		'create': 1,
-		'doctype': u'DocPerm',
-		'permlevel': 0,
-		'role': u'HR Manager',
-		'submit': 1,
-		'write': 1
-	},
-
-	# DocPerm
-	{
-		'amend': 1,
-		'cancel': 1,
-		'create': 1,
-		'doctype': u'DocPerm',
-		'permlevel': 0,
-		'role': u'HR User',
-		'submit': 1,
-		'write': 1
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'details',
-		'fieldtype': u'Section Break',
-		'label': u'Details',
-		'oldfieldtype': u'Section Break',
-		'permlevel': 0
-	},
-
-	# DocField
-	{
-		'colour': u'White:FFF',
-		'default': u'Draft',
-		'doctype': u'DocField',
-		'fieldname': u'approval_status',
-		'fieldtype': u'Select',
-		'in_filter': 1,
-		'label': u'Approval Status',
-		'no_copy': 1,
-		'oldfieldname': u'approval_status',
-		'oldfieldtype': u'Select',
-		'options': u'\nDraft\nSubmitted\nApproved \nRejected\nCancelled',
-		'permlevel': 1,
-		'search_index': 1
-	},
-
-	# DocField
-	{
-		'colour': u'White:FFF',
-		'doctype': u'DocField',
-		'fieldname': u'employee',
-		'fieldtype': u'Link',
-		'in_filter': 1,
-		'label': u'From Employee',
-		'oldfieldname': u'employee',
-		'oldfieldtype': u'Link',
-		'options': u'Employee',
-		'permlevel': 0,
-		'reqd': 1,
-		'search_index': 1,
-		'trigger': u'Client'
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'employee_name',
-		'fieldtype': u'Data',
-		'in_filter': 1,
-		'label': u'Employee Name',
-		'oldfieldname': u'employee_name',
-		'oldfieldtype': u'Data',
-		'permlevel': 1,
-		'search_index': 0,
-		'width': u'150px'
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'fiscal_year',
-		'fieldtype': u'Select',
-		'in_filter': 1,
-		'label': u'Fiscal Year',
-		'oldfieldname': u'fiscal_year',
-		'oldfieldtype': u'Select',
-		'options': u'link:Fiscal Year',
-		'permlevel': 0,
-		'reqd': 1
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'company',
-		'fieldtype': u'Select',
-		'in_filter': 1,
-		'label': u'Company',
-		'oldfieldname': u'company',
-		'oldfieldtype': u'Link',
-		'options': u'link:Company',
-		'permlevel': 0,
-		'reqd': 1
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'column_break0',
-		'fieldtype': u'Column Break',
-		'oldfieldtype': u'Column Break',
-		'permlevel': 0,
-		'width': u'50%'
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'posting_date',
-		'fieldtype': u'Date',
-		'in_filter': 1,
-		'label': u'Posting Date',
-		'oldfieldname': u'posting_date',
-		'oldfieldtype': u'Date',
-		'permlevel': 0,
-		'reqd': 1
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'exp_approver',
-		'fieldtype': u'Select',
-		'label': u'Approver',
-		'oldfieldname': u'exp_approver',
-		'oldfieldtype': u'Select',
-		'permlevel': 0,
-		'width': u'160px'
-	},
-
-	# DocField
-	{
-		'allow_on_submit': 1,
-		'colour': u'White:FFF',
-		'doctype': u'DocField',
-		'fieldname': u'remark',
-		'fieldtype': u'Small Text',
-		'label': u'Remark',
-		'no_copy': 1,
-		'oldfieldname': u'remark',
-		'oldfieldtype': u'Small Text',
-		'permlevel': 0
-	},
-
-	# DocField
-	{
-		'colour': u'White:FFF',
-		'doctype': u'DocField',
-		'fieldname': u'amended_from',
-		'fieldtype': u'Data',
-		'label': u'Amended From',
-		'no_copy': 1,
-		'oldfieldname': u'amended_from',
-		'oldfieldtype': u'Data',
-		'permlevel': 1,
-		'print_hide': 1,
-		'report_hide': 1,
-		'width': u'160px'
-	},
-
-	# DocField
-	{
-		'colour': u'White:FFF',
-		'doctype': u'DocField',
-		'fieldname': u'amendment_date',
-		'fieldtype': u'Date',
-		'label': u'Amendment Date',
-		'no_copy': 1,
-		'oldfieldname': u'amendment_date',
-		'oldfieldtype': u'Date',
-		'permlevel': 1,
-		'print_hide': 1,
-		'report_hide': 1,
-		'width': u'160px'
-	},
-
-	# DocField
-	{
-		'allow_on_submit': 1,
-		'doctype': u'DocField',
-		'fieldname': u'approve',
-		'fieldtype': u'Button',
-		'hidden': 1,
-		'label': u'Approve',
-		'oldfieldtype': u'Button',
-		'permlevel': 0,
-		'print_hide': 1,
-		'trigger': u'Client'
-	},
-
-	# DocField
-	{
-		'allow_on_submit': 1,
-		'doctype': u'DocField',
-		'fieldname': u'reject',
-		'fieldtype': u'Button',
-		'hidden': 1,
-		'label': u'Reject',
-		'oldfieldtype': u'Button',
-		'permlevel': 0,
-		'print_hide': 1,
-		'trigger': u'Client'
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'expense_details',
-		'fieldtype': u'Section Break',
-		'label': u'Expense Details',
-		'oldfieldtype': u'Section Break',
-		'permlevel': 0
-	},
-
-	# DocField
-	{
-		'allow_on_submit': 1,
-		'colour': u'White:FFF',
-		'doctype': u'DocField',
-		'fieldname': u'calculate_total_amount',
-		'fieldtype': u'Button',
-		'label': u'Calculate Total Amount',
-		'oldfieldtype': u'Button',
-		'permlevel': 0,
-		'print_hide': 1,
-		'report_hide': 1,
-		'trigger': u'Client'
-	},
-
-	# DocField
-	{
-		'colour': u'White:FFF',
-		'doctype': u'DocField',
-		'fieldname': u'total_claimed_amount',
-		'fieldtype': u'Currency',
-		'in_filter': 0,
-		'label': u'Total Claimed Amount',
-		'no_copy': 1,
-		'oldfieldname': u'total_claimed_amount',
-		'oldfieldtype': u'Currency',
-		'permlevel': 1,
-		'reqd': 0,
-		'width': u'160px'
-	},
-
-	# DocField
-	{
-		'colour': u'White:FFF',
-		'doctype': u'DocField',
-		'fieldname': u'total_sanctioned_amount',
-		'fieldtype': u'Currency',
-		'in_filter': 0,
-		'label': u'Total Sanctioned Amount',
-		'no_copy': 1,
-		'oldfieldname': u'total_sanctioned_amount',
-		'oldfieldtype': u'Currency',
-		'permlevel': 1,
-		'width': u'160px'
-	},
-
-	# DocField
-	{
-		'allow_on_submit': 1,
-		'doctype': u'DocField',
-		'fieldname': u'update_voucher',
-		'fieldtype': u'Button',
-		'hidden': 1,
-		'label': u'Update Voucher',
-		'oldfieldtype': u'Button',
-		'permlevel': 0,
-		'print_hide': 1,
-		'trigger': u'Client'
-	},
-
-	# DocField
-	{
-		'allow_on_submit': 1,
-		'doctype': u'DocField',
-		'fieldname': u'expense_voucher_details',
-		'fieldtype': u'Table',
-		'label': u'Expense Claim Details',
-		'oldfieldname': u'expense_voucher_details',
-		'oldfieldtype': u'Table',
-		'options': u'Expense Claim Detail',
-		'permlevel': 0
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'email_id',
-		'fieldtype': u'Data',
-		'hidden': 1,
-		'label': u'Employees Email Id',
-		'oldfieldname': u'email_id',
-		'oldfieldtype': u'Data',
-		'permlevel': 0,
-		'print_hide': 1
-	}
+ {
+  "owner": "harshada@webnotestech.com", 
+  "docstatus": 0, 
+  "creation": "2012-12-05 14:11:53", 
+  "modified_by": "Administrator", 
+  "modified": "2012-12-05 14:22:27"
+ }, 
+ {
+  "is_submittable": 1, 
+  "autoname": "EXP.######", 
+  "name": "__common__", 
+  "default_print_format": "Standard", 
+  "search_fields": "approval_status,employee,employee_name", 
+  "module": "HR", 
+  "doctype": "DocType"
+ }, 
+ {
+  "name": "__common__", 
+  "parent": "Expense Claim", 
+  "doctype": "DocField", 
+  "parenttype": "DocType", 
+  "parentfield": "fields"
+ }, 
+ {
+  "name": "__common__", 
+  "parent": "Expense Claim", 
+  "read": 1, 
+  "doctype": "DocPerm", 
+  "parenttype": "DocType", 
+  "parentfield": "permissions"
+ }, 
+ {
+  "name": "Expense Claim", 
+  "doctype": "DocType"
+ }, 
+ {
+  "oldfieldtype": "Section Break", 
+  "doctype": "DocField", 
+  "label": "Details", 
+  "fieldname": "details", 
+  "fieldtype": "Section Break", 
+  "permlevel": 0
+ }, 
+ {
+  "permlevel": 1, 
+  "no_copy": 1, 
+  "oldfieldtype": "Select", 
+  "colour": "White:FFF", 
+  "doctype": "DocField", 
+  "label": "Approval Status", 
+  "oldfieldname": "approval_status", 
+  "default": "Draft", 
+  "fieldname": "approval_status", 
+  "fieldtype": "Select", 
+  "search_index": 1, 
+  "options": "\nDraft\nApproved\nRejected", 
+  "in_filter": 1
+ }, 
+ {
+  "oldfieldtype": "Select", 
+  "doctype": "DocField", 
+  "label": "Approver", 
+  "oldfieldname": "exp_approver", 
+  "width": "160px", 
+  "fieldname": "exp_approver", 
+  "fieldtype": "Select", 
+  "permlevel": 0
+ }, 
+ {
+  "oldfieldtype": "Date", 
+  "doctype": "DocField", 
+  "label": "Posting Date", 
+  "oldfieldname": "posting_date", 
+  "fieldname": "posting_date", 
+  "fieldtype": "Date", 
+  "reqd": 1, 
+  "permlevel": 0, 
+  "in_filter": 1
+ }, 
+ {
+  "oldfieldtype": "Column Break", 
+  "doctype": "DocField", 
+  "width": "50%", 
+  "fieldname": "column_break0", 
+  "fieldtype": "Column Break", 
+  "permlevel": 0
+ }, 
+ {
+  "oldfieldtype": "Link", 
+  "colour": "White:FFF", 
+  "doctype": "DocField", 
+  "label": "From Employee", 
+  "oldfieldname": "employee", 
+  "permlevel": 0, 
+  "trigger": "Client", 
+  "fieldname": "employee", 
+  "fieldtype": "Link", 
+  "search_index": 1, 
+  "reqd": 1, 
+  "options": "Employee", 
+  "in_filter": 1
+ }, 
+ {
+  "oldfieldtype": "Data", 
+  "doctype": "DocField", 
+  "label": "Employee Name", 
+  "oldfieldname": "employee_name", 
+  "width": "150px", 
+  "fieldname": "employee_name", 
+  "fieldtype": "Data", 
+  "search_index": 0, 
+  "permlevel": 1, 
+  "in_filter": 1
+ }, 
+ {
+  "no_copy": 1, 
+  "oldfieldtype": "Small Text", 
+  "colour": "White:FFF", 
+  "allow_on_submit": 0, 
+  "doctype": "DocField", 
+  "label": "Remark", 
+  "oldfieldname": "remark", 
+  "fieldname": "remark", 
+  "fieldtype": "Small Text", 
+  "permlevel": 0
+ }, 
+ {
+  "print_hide": 1, 
+  "no_copy": 1, 
+  "oldfieldtype": "Data", 
+  "colour": "White:FFF", 
+  "doctype": "DocField", 
+  "label": "Amended From", 
+  "oldfieldname": "amended_from", 
+  "width": "160px", 
+  "fieldname": "amended_from", 
+  "fieldtype": "Data", 
+  "permlevel": 1, 
+  "report_hide": 1
+ }, 
+ {
+  "print_hide": 1, 
+  "no_copy": 1, 
+  "oldfieldtype": "Date", 
+  "colour": "White:FFF", 
+  "doctype": "DocField", 
+  "label": "Amendment Date", 
+  "oldfieldname": "amendment_date", 
+  "width": "160px", 
+  "fieldname": "amendment_date", 
+  "fieldtype": "Date", 
+  "permlevel": 1, 
+  "report_hide": 1
+ }, 
+ {
+  "oldfieldtype": "Section Break", 
+  "doctype": "DocField", 
+  "label": "Expense Details", 
+  "fieldname": "expense_details", 
+  "fieldtype": "Section Break", 
+  "permlevel": 0
+ }, 
+ {
+  "oldfieldtype": "Table", 
+  "allow_on_submit": 0, 
+  "doctype": "DocField", 
+  "label": "Expense Claim Details", 
+  "oldfieldname": "expense_voucher_details", 
+  "options": "Expense Claim Detail", 
+  "fieldname": "expense_voucher_details", 
+  "fieldtype": "Table", 
+  "permlevel": 0
+ }, 
+ {
+  "no_copy": 1, 
+  "oldfieldtype": "Currency", 
+  "colour": "White:FFF", 
+  "doctype": "DocField", 
+  "label": "Total Claimed Amount", 
+  "oldfieldname": "total_claimed_amount", 
+  "width": "160px", 
+  "fieldname": "total_claimed_amount", 
+  "fieldtype": "Currency", 
+  "reqd": 0, 
+  "permlevel": 1, 
+  "in_filter": 0
+ }, 
+ {
+  "no_copy": 1, 
+  "oldfieldtype": "Currency", 
+  "colour": "White:FFF", 
+  "doctype": "DocField", 
+  "label": "Total Sanctioned Amount", 
+  "oldfieldname": "total_sanctioned_amount", 
+  "width": "160px", 
+  "fieldname": "total_sanctioned_amount", 
+  "fieldtype": "Currency", 
+  "permlevel": 1, 
+  "in_filter": 0
+ }, 
+ {
+  "print_hide": 1, 
+  "oldfieldtype": "Data", 
+  "doctype": "DocField", 
+  "label": "Employees Email Id", 
+  "oldfieldname": "email_id", 
+  "fieldname": "email_id", 
+  "fieldtype": "Data", 
+  "hidden": 1, 
+  "permlevel": 0
+ }, 
+ {
+  "oldfieldtype": "Select", 
+  "doctype": "DocField", 
+  "label": "Fiscal Year", 
+  "oldfieldname": "fiscal_year", 
+  "options": "link:Fiscal Year", 
+  "fieldname": "fiscal_year", 
+  "fieldtype": "Select", 
+  "reqd": 1, 
+  "permlevel": 0, 
+  "in_filter": 1
+ }, 
+ {
+  "oldfieldtype": "Link", 
+  "doctype": "DocField", 
+  "label": "Company", 
+  "oldfieldname": "company", 
+  "options": "link:Company", 
+  "fieldname": "company", 
+  "fieldtype": "Select", 
+  "reqd": 1, 
+  "permlevel": 0, 
+  "in_filter": 1
+ }, 
+ {
+  "create": 1, 
+  "doctype": "DocPerm", 
+  "write": 1, 
+  "role": "Employee", 
+  "permlevel": 0, 
+  "match": "owner"
+ }, 
+ {
+  "amend": 1, 
+  "create": 1, 
+  "doctype": "DocPerm", 
+  "submit": 1, 
+  "write": 1, 
+  "cancel": 1, 
+  "role": "Expense Approver", 
+  "permlevel": 0, 
+  "match": "exp_approver:user"
+ }, 
+ {
+  "amend": 1, 
+  "create": 1, 
+  "doctype": "DocPerm", 
+  "submit": 1, 
+  "write": 1, 
+  "cancel": 1, 
+  "role": "HR User", 
+  "permlevel": 0
+ }, 
+ {
+  "doctype": "DocPerm", 
+  "role": "All", 
+  "permlevel": 1
+ }
 ]
\ No newline at end of file
diff --git a/hr/doctype/expense_claim_detail/expense_claim_detail.txt b/hr/doctype/expense_claim_detail/expense_claim_detail.txt
index a11ce5c..f28811f 100644
--- a/hr/doctype/expense_claim_detail/expense_claim_detail.txt
+++ b/hr/doctype/expense_claim_detail/expense_claim_detail.txt
@@ -1,103 +1,80 @@
-# DocType, Expense Claim Detail
 [
-
-	# These values are common in all dictionaries
-	{
-		'creation': '2012-03-27 14:35:56',
-		'docstatus': 0,
-		'modified': '2012-03-27 14:35:56',
-		'modified_by': u'Administrator',
-		'owner': u'harshada@webnotestech.com'
-	},
-
-	# These values are common for all DocType
-	{
-		'colour': u'White:FFF',
-		'doctype': 'DocType',
-		'istable': 1,
-		'module': u'HR',
-		'name': '__common__',
-		'section_style': u'Simple',
-		'server_code_error': u' ',
-		'version': 5
-	},
-
-	# These values are common for all DocField
-	{
-		'doctype': u'DocField',
-		'name': '__common__',
-		'parent': u'Expense Claim Detail',
-		'parentfield': u'fields',
-		'parenttype': u'DocType',
-		'permlevel': 0
-	},
-
-	# DocType, Expense Claim Detail
-	{
-		'doctype': 'DocType',
-		'name': u'Expense Claim Detail'
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'expense_date',
-		'fieldtype': u'Date',
-		'label': u'Expense Date',
-		'oldfieldname': u'expense_date',
-		'oldfieldtype': u'Date',
-		'reqd': 0,
-		'width': u'150px'
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'expense_type',
-		'fieldtype': u'Link',
-		'label': u'Expense Claim Type',
-		'oldfieldname': u'expense_type',
-		'oldfieldtype': u'Link',
-		'options': u'Expense Claim Type',
-		'reqd': 1,
-		'width': u'150px'
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'description',
-		'fieldtype': u'Small Text',
-		'label': u'Description',
-		'oldfieldname': u'description',
-		'oldfieldtype': u'Small Text',
-		'width': u'300px'
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'claim_amount',
-		'fieldtype': u'Currency',
-		'label': u'Claim Amount',
-		'oldfieldname': u'claim_amount',
-		'oldfieldtype': u'Currency',
-		'reqd': 1,
-		'trigger': u'Client',
-		'width': u'150px'
-	},
-
-	# DocField
-	{
-		'allow_on_submit': 1,
-		'doctype': u'DocField',
-		'fieldname': u'sanctioned_amount',
-		'fieldtype': u'Currency',
-		'label': u'Sanctioned Amount',
-		'no_copy': 1,
-		'oldfieldname': u'sanctioned_amount',
-		'oldfieldtype': u'Currency',
-		'trigger': u'Client',
-		'width': u'150px'
-	}
+ {
+  "owner": "harshada@webnotestech.com", 
+  "docstatus": 0, 
+  "creation": "2012-07-03 13:30:39", 
+  "modified_by": "Administrator", 
+  "modified": "2012-12-05 14:22:03"
+ }, 
+ {
+  "istable": 1, 
+  "name": "__common__", 
+  "doctype": "DocType", 
+  "module": "HR"
+ }, 
+ {
+  "name": "__common__", 
+  "parent": "Expense Claim Detail", 
+  "doctype": "DocField", 
+  "parenttype": "DocType", 
+  "permlevel": 0, 
+  "parentfield": "fields"
+ }, 
+ {
+  "name": "Expense Claim Detail", 
+  "doctype": "DocType"
+ }, 
+ {
+  "oldfieldtype": "Date", 
+  "doctype": "DocField", 
+  "label": "Expense Date", 
+  "oldfieldname": "expense_date", 
+  "width": "150px", 
+  "fieldname": "expense_date", 
+  "fieldtype": "Date", 
+  "reqd": 0
+ }, 
+ {
+  "oldfieldtype": "Link", 
+  "doctype": "DocField", 
+  "label": "Expense Claim Type", 
+  "oldfieldname": "expense_type", 
+  "width": "150px", 
+  "fieldname": "expense_type", 
+  "fieldtype": "Select", 
+  "reqd": 1, 
+  "options": "link:Expense Claim Type"
+ }, 
+ {
+  "oldfieldtype": "Small Text", 
+  "doctype": "DocField", 
+  "label": "Description", 
+  "oldfieldname": "description", 
+  "width": "300px", 
+  "fieldname": "description", 
+  "fieldtype": "Small Text"
+ }, 
+ {
+  "oldfieldtype": "Currency", 
+  "doctype": "DocField", 
+  "label": "Claim Amount", 
+  "oldfieldname": "claim_amount", 
+  "width": "150px", 
+  "trigger": "Client", 
+  "fieldname": "claim_amount", 
+  "fieldtype": "Currency", 
+  "reqd": 1
+ }, 
+ {
+  "no_copy": 1, 
+  "oldfieldtype": "Currency", 
+  "allow_on_submit": 0, 
+  "doctype": "DocField", 
+  "label": "Sanctioned Amount", 
+  "oldfieldname": "sanctioned_amount", 
+  "width": "150px", 
+  "trigger": "Client", 
+  "fieldname": "sanctioned_amount", 
+  "fieldtype": "Currency"
+ }
 ]
\ No newline at end of file
diff --git a/hr/doctype/leave_application/leave_application.js b/hr/doctype/leave_application/leave_application.js
index 00df476..2d71aac 100755
--- a/hr/doctype/leave_application/leave_application.js
+++ b/hr/doctype/leave_application/leave_application.js
@@ -8,14 +8,23 @@
 // 
 // 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
+// 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/>.
+// along with this program.	If not, see <http://www.gnu.org/licenses/>.
+
+cur_frm.add_fetch('employee','employee_name','employee_name');
 
 cur_frm.cscript.onload = function(doc, dt, dn) {
-  if(!doc.posting_date) set_multiple(dt,dn,{posting_date:get_today()});
+	if(!doc.posting_date) 
+		set_multiple(dt,dn,{posting_date:get_today()});
+	cur_frm.call({
+		method:"get_approver_list",
+		callback: function(r) {
+			cur_frm.set_df_property("leave_approver", "options", r.message);
+		}
+	});
 }
 
 cur_frm.cscript.refresh = function(doc, dt, dn) {
@@ -23,14 +32,16 @@
 	if(doc.__islocal && !in_list(user_roles, "HR User")) {
 		cur_frm.set_intro("Fill the form and save it")
 	} else {
-		if(in_list(user_roles, "HR User")) {
-			if(doc.status=="Open") {
-				cur_frm.set_intro("Please Approve (and Submit) or Reject, or re-assign to applicant for further review.");				
+		if(doc.status=="Open") {
+			if(user==doc.leave_approver) {
+				cur_frm.set_intro("You are the Leave Approver for this record. Please Update the 'Status' and Save");
+				cur_frm.toggle_enable("status", true);
+			} else {
+				cur_frm.set_intro("This Leave Application is pending approval. Only the Leave Apporver can update status.")
+				cur_frm.toggle_enable("status", false);
 			}
 		} else {
-			if(doc.status=="Open") {
-				cur_frm.set_intro("Leave application is pending approval.");
-			} else if(doc.status=="Approved") {
+ 			if(doc.status=="Approved") {
 				cur_frm.set_intro("Leave application has been approved.");
 			} else if(doc.status=="Rejected") {
 				cur_frm.set_intro("Leave application has been rejected.");
@@ -38,61 +49,67 @@
 		}
 	}
 	
-	if(doc.status=="Approved" && doc.docstatus!=1) {
+	if(doc.status=="Approved" && doc.docstatus==0) {
 		cur_frm.savesubmit()
 	}
 }
 
-cur_frm.add_fetch('employee','employee_name','employee_name');
-
 cur_frm.cscript.employee = function (doc, dt, dn){
-  get_leave_balance(doc, dt, dn);
+	get_leave_balance(doc, dt, dn);
 }
 
 cur_frm.cscript.fiscal_year = function (doc, dt, dn){
-  get_leave_balance(doc, dt, dn);
+	get_leave_balance(doc, dt, dn);
 }
 
 cur_frm.cscript.leave_type = function (doc, dt, dn){
-  get_leave_balance(doc, dt, dn);
+	get_leave_balance(doc, dt, dn);
 }
 
 cur_frm.cscript.half_day = function(doc, dt, dn) {
-  if(doc.from_date) {
-    set_multiple(dt,dn,{to_date:doc.from_date});
-    calculate_total_days(doc, dt, dn);
-  }
+	if(doc.from_date) {
+		set_multiple(dt,dn,{to_date:doc.from_date});
+		calculate_total_days(doc, dt, dn);
+	}
 }
 
 cur_frm.cscript.from_date = function(doc, dt, dn) {
-  if(cint(doc.half_day) == 1){
-    set_multiple(dt,dn,{to_date:doc.from_date});
-  }
-  calculate_total_days(doc, dt, dn);
+	if(cint(doc.half_day) == 1){
+		set_multiple(dt,dn,{to_date:doc.from_date});
+	}
+	calculate_total_days(doc, dt, dn);
 }
 
 cur_frm.cscript.to_date = function(doc, dt, dn) {
-  if(cint(doc.half_day) == 1 && cstr(doc.from_date) && doc.from_date != doc.to_date){
-    msgprint("To Date should be same as From Date for Half Day leave");
-    set_multiple(dt,dn,{to_date:doc.from_date});    
-  }
-  calculate_total_days(doc, dt, dn);
+	if(cint(doc.half_day) == 1 && cstr(doc.from_date) && doc.from_date != doc.to_date){
+		msgprint("To Date should be same as From Date for Half Day leave");
+		set_multiple(dt,dn,{to_date:doc.from_date});		
+	}
+	calculate_total_days(doc, dt, dn);
 }
-
+	
 get_leave_balance = function(doc, dt, dn) {
-  if(doc.employee && doc.leave_type && doc.fiscal_year)
-    get_server_fields('get_leave_balance', '','', doc, dt, dn, 1);
+	if(doc.employee && doc.leave_type && doc.fiscal_year) {
+		cur_frm.call({
+			method: "get_leave_balance",
+			args: {
+				employee: doc.employee,
+				fiscal_year: doc.fiscal_year,
+				leave_type: doc.leave_type
+			}
+		})		
+	}
 }
 
 calculate_total_days = function(doc, dt, dn) {
-  if(doc.from_date && doc.to_date){
-    if(cint(doc.half_day) == 1) set_multiple(dt,dn,{total_leave_days:0.5});
-    else{
-      //d = new DateFn();
-      //set_multiple(dt,dn,{total_leave_days:d.get_diff(d.str_to_obj(doc.to_date),d.str_to_obj(doc.from_date))+1});
-      get_server_fields('get_total_leave_days', '', '', doc, dt, dn, 1);
-    }
-  }
+	if(doc.from_date && doc.to_date){
+		if(cint(doc.half_day) == 1) set_multiple(dt,dn,{total_leave_days:0.5});
+		else{
+			//d = new DateFn();
+			//set_multiple(dt,dn,{total_leave_days:d.get_diff(d.str_to_obj(doc.to_date),d.str_to_obj(doc.from_date))+1});
+			get_server_fields('get_total_leave_days', '', '', doc, dt, dn, 1);
+		}
+	}
 }
 
 cur_frm.fields_dict.employee.get_query = erpnext.utils.employee_query;
\ No newline at end of file
diff --git a/hr/doctype/leave_application/leave_application.py b/hr/doctype/leave_application/leave_application.py
index 91c9d8c..cdddb9f 100755
--- a/hr/doctype/leave_application/leave_application.py
+++ b/hr/doctype/leave_application/leave_application.py
@@ -30,14 +30,6 @@
 		self.doc = doc
 		self.doclist = doclist 
 
-	def get_leave_balance(self):
-		leave_all = sql("select total_leaves_allocated from `tabLeave Allocation` where employee = '%s' and leave_type = '%s' and fiscal_year = '%s' and docstatus = 1" % (self.doc.employee, self.doc.leave_type, self.doc.fiscal_year))
-		leave_all = leave_all and flt(leave_all[0][0]) or 0
-		leave_app = sql("select SUM(total_leave_days) from `tabLeave Application` where employee = '%s' and leave_type = '%s' and fiscal_year = '%s' and docstatus = 1" % (self.doc.employee, self.doc.leave_type, self.doc.fiscal_year))
-		leave_app = leave_app and flt(leave_app[0][0]) or 0
-		ret = {'leave_balance':leave_all - leave_app}
-		return ret
-
 	def get_holidays(self):
 		"""
 			get total holidays
@@ -71,7 +63,8 @@
 
 	def validate_balance_leaves(self):
 		if self.doc.from_date and self.doc.to_date and not self.is_lwp():
-			bal = self.get_leave_balance()
+			bal = get_leave_balance(self.doc.leave_type, self.doc.employee, 
+				self.doc.fiscal_year)["leave_balance"]
 			tot_leaves = self.get_total_leave_days()
 			bal, tot_leaves = bal, tot_leaves
 			webnotes.conn.set(self.doc,'leave_balance',flt(bal['leave_balance']))
@@ -98,6 +91,9 @@
 			raise Exception
 
 	def validate(self):
+		if self.doc.leave_approver == self.doc.owner:
+			webnotes.msgprint("""Self Approval is not allowed.""", raise_exception=1)
+
 		self.validate_to_date()
 		self.validate_balance_leaves()
 		self.validate_leave_overlap()
@@ -107,3 +103,30 @@
 		if self.doc.status != "Approved":
 			webnotes.msgprint("""Only Approved Leave Applications can be Submitted.""",
 				raise_exception=True)
+
+@webnotes.whitelist()
+def get_leave_balance(employee, leave_type, fiscal_year):
+	leave_all = webnotes.conn.sql("""select total_leaves_allocated 
+		from `tabLeave Allocation` where employee = %s and leave_type = %s
+		and fiscal_year = %s and docstatus = 1""", (employee, 
+			leave_type, fiscal_year))
+
+	leave_all = leave_all and flt(leave_all[0][0]) or 0
+	
+	leave_app = webnotes.conn.sql("""select SUM(total_leave_days) 
+		from `tabLeave Application` 
+		where employee = %s and leave_type = %s and fiscal_year = %s
+		and docstatus = 1""", (employee, leave_type, fiscal_year))
+	leave_app = leave_app and flt(leave_app[0][0]) or 0
+
+	ret = {'leave_balance':leave_all - leave_app}
+	return ret
+
+@webnotes.whitelist()
+def get_approver_list():
+	roles = [r[0] for r in webnotes.conn.sql("""select distinct parent from `tabUserRole`
+		where role='Leave Approver'""")]
+	if not roles:
+		webnotes.msgprint("No Leave Approvers. Please assign 'Leave Approver' Role to atleast one user.")
+		
+	return roles
diff --git a/hr/doctype/leave_application/leave_application.txt b/hr/doctype/leave_application/leave_application.txt
index 6a33df6..b205d18 100644
--- a/hr/doctype/leave_application/leave_application.txt
+++ b/hr/doctype/leave_application/leave_application.txt
@@ -2,9 +2,9 @@
  {
   "owner": "Administrator", 
   "docstatus": 0, 
-  "creation": "2012-11-02 17:16:54", 
+  "creation": "2012-12-05 14:11:53", 
   "modified_by": "Administrator", 
-  "modified": "2012-11-30 12:17:27"
+  "modified": "2012-12-05 17:38:26"
  }, 
  {
   "is_submittable": 1, 
@@ -45,6 +45,15 @@
   "permlevel": 3
  }, 
  {
+  "description": "Leave can be approved by users with Role, \"Leave Approver\"", 
+  "colour": "White:FFF", 
+  "doctype": "DocField", 
+  "label": "Leave Approver", 
+  "fieldname": "leave_approver", 
+  "fieldtype": "Select", 
+  "permlevel": 0
+ }, 
+ {
   "search_index": 1, 
   "doctype": "DocField", 
   "label": "Leave Type", 
@@ -216,12 +225,29 @@
   "permlevel": 0
  }, 
  {
+  "amend": 1, 
+  "create": 1, 
+  "doctype": "DocPerm", 
+  "submit": 1, 
+  "write": 1, 
+  "role": "Leave Approver", 
+  "cancel": 1, 
+  "permlevel": 0, 
+  "match": "leave_approver:user"
+ }, 
+ {
+  "doctype": "DocPerm", 
+  "write": 1, 
+  "role": "HR User", 
+  "permlevel": 2
+ }, 
+ {
   "amend": 0, 
   "create": 0, 
   "doctype": "DocPerm", 
   "submit": 0, 
   "write": 1, 
-  "role": "HR User", 
+  "role": "Leave Approver", 
   "cancel": 0, 
   "permlevel": 2
  }, 
@@ -229,11 +255,5 @@
   "doctype": "DocPerm", 
   "role": "All", 
   "permlevel": 3
- }, 
- {
-  "doctype": "DocPerm", 
-  "write": 1, 
-  "role": "HR User", 
-  "permlevel": 3
  }
 ]
\ No newline at end of file
diff --git a/patches/december_2012/expense_leave_reload.py b/patches/december_2012/expense_leave_reload.py
new file mode 100644
index 0000000..06c67e6
--- /dev/null
+++ b/patches/december_2012/expense_leave_reload.py
@@ -0,0 +1,26 @@
+import webnotes
+
+def execute():
+	# new roles
+	roles = [r[0] for r in webnotes.conn.sql("""select name from tabRole""")]
+	if not "Leave Approver" in roles:
+		webnotes.model_wrapper([{"doctype":"Role", "role_name":"Leave Approver", 
+			"__islocal":1, "module":"HR"}]).save()
+	if not "Expense Approver" in roles:
+		webnotes.model_wrapper([{"doctype":"Role", "role_name":"Expense Approver", 
+			"__islocal":1, "module":"HR"}]).save()
+
+	# reload
+	webnotes.clear_perms("Leave Application")
+	webnotes.reload_doc("hr", "doctype", "leave_application")
+
+	webnotes.clear_perms("Expense Claim")
+	webnotes.reload_doc("hr", "doctype", "expense_claim")
+	
+	# remove extra space in Approved Expense Vouchers
+	webnotes.conn.sql("""update `tabExpense Claim` set approval_status='Approved'
+		where approval_status='Approved '""")
+
+	webnotes.conn.commit()
+	for t in ['__CacheItem', '__SessionCache', 'tabSupport Ticket Response']:
+		webnotes.conn.sql("drop table if exists `%s`" % t)
\ No newline at end of file
diff --git a/patches/december_2012/reload_debtors_creditors_ledger.py b/patches/december_2012/reload_debtors_creditors_ledger.py
new file mode 100644
index 0000000..7f88a6f
--- /dev/null
+++ b/patches/december_2012/reload_debtors_creditors_ledger.py
@@ -0,0 +1,5 @@
+def execute():
+	import webnotes
+	from webnotes.modules import reload_doc
+	reload_doc("accounts", "search_criteria", "debtors_ledger")
+	reload_doc("accounts", "search_criteria", "creditors_ledger")
\ No newline at end of file
diff --git a/patches/patch_list.py b/patches/patch_list.py
index ce03fb2..38847eb 100644
--- a/patches/patch_list.py
+++ b/patches/patch_list.py
@@ -711,10 +711,18 @@
 	},
 	{
 		'patch_module': 'patches.december_2012',
+		'patch_file': 'expense_leave_reload',
+	},
+	{
+		'patch_module': 'patches.december_2012',
 		'patch_file': 'repost_ordered_qty',
 	},
 	{
 		'patch_module': 'patches.december_2012',
 		'patch_file': 'repost_projected_qty',
 	},
+	{
+		'patch_module': 'patches.december_2012',
+		'patch_file': 'reload_debtors_creditors_ledger',
+	},
 ]
\ No newline at end of file
diff --git a/stock/doctype/packing_slip/packing_slip.js b/stock/doctype/packing_slip/packing_slip.js
index d3cf9be..7e26a09 100644
--- a/stock/doctype/packing_slip/packing_slip.js
+++ b/stock/doctype/packing_slip/packing_slip.js
@@ -43,8 +43,8 @@
 }
 
 
-cur_frm.cscript.onload = function(doc, cdt, cdn) {
-	if(doc.delivery_note) {
+cur_frm.cscript.onload_post_render = function(doc, cdt, cdn) {
+	if(doc.delivery_note && doc.__islocal) {
 		var ps_detail = getchildren('Packing Slip Item', doc.name, 'item_details');
 		if(!(flt(ps_detail[0].net_weight) && cstr(ps_detail[0].weight_uom))) {
 			cur_frm.cscript.update_item_details(doc);
diff --git a/stock/doctype/packing_slip/packing_slip.py b/stock/doctype/packing_slip/packing_slip.py
index 9e544b6..7ef7d36 100644
--- a/stock/doctype/packing_slip/packing_slip.py
+++ b/stock/doctype/packing_slip/packing_slip.py
@@ -16,7 +16,7 @@
 
 from __future__ import unicode_literals
 import webnotes
-from webnotes.utils import flt, cint
+from webnotes.utils import flt, cint, now
 
 class DocType:
 	def __init__(self, d, dl):
@@ -56,6 +56,15 @@
 			Validate if case nos overlap
 			If they do, recommend next case no.
 		"""
+		if not cint(self.doc.from_case_no):
+			webnotes.msgprint("Please specify a valid 'From Case No.'", raise_exception=1)
+		elif not self.doc.to_case_no:
+			self.doc.to_case_no = self.doc.from_case_no
+		elif self.doc.from_case_no > self.doc.to_case_no:
+			webnotes.msgprint("'To Case No.' cannot be less than 'From Case No.'",
+				raise_exception=1)
+		
+		
 		res = webnotes.conn.sql("""\
 			SELECT name FROM `tabPacking Slip`
 			WHERE delivery_note = %(delivery_note)s AND docstatus = 1 AND
@@ -92,16 +101,24 @@
 		item_codes = ", ".join([('"' + d.item_code + '"') for d in
 			self.doclist])
 		
+		items = [d.item_code for d in self.doclist.get({"parentfield": "item_details"})]
+		
 		if not item_codes: webnotes.msgprint("No Items to Pack",
 				raise_exception=1)
-
-		res = webnotes.conn.sql("""\
-			SELECT item_code, IFNULL(SUM(qty), 0) as qty, IFNULL(packed_qty, 0) as packed_qty, stock_uom
-			FROM `tabDelivery Note Item`
-			WHERE parent = "%s" AND item_code IN (%s)
-			GROUP BY item_code""" % (self.doc.delivery_note, item_codes),
-			as_dict=1)
-
+		
+		# gets item code, qty per item code, latest packed qty per item code and stock uom
+		res = webnotes.conn.sql("""select item_code, ifnull(sum(qty), 0) as qty,
+			(select sum(ifnull(psi.qty, 0) * (abs(ps.to_case_no - ps.from_case_no) + 1))
+				from `tabPacking Slip` ps, `tabPacking Slip Item` psi
+				where ps.name = psi.parent and ps.docstatus = 1
+				and ps.delivery_note = dni.parent and psi.item_code=dni.item_code)
+					as packed_qty,
+			stock_uom
+			from `tabDelivery Note Item` dni
+			where parent=%s and item_code in (%s)
+			group by item_code""" % ("%s", ", ".join(["%s"]*len(items))),
+			tuple([self.doc.delivery_note] + items), as_dict=1, debug=1)
+			
 		ps_item_qty = dict([[d.item_code, d.qty] for d in self.doclist])
 
 		no_of_cases = cint(self.doc.to_case_no) - cint(self.doc.from_case_no) + 1
@@ -148,28 +165,29 @@
 		dn_details, ps_item_qty, no_of_cases = self.get_details_for_packing()
 
 		for item in dn_details:
-			if event=='submit':
-				new_packed_qty = flt(item['packed_qty']) + (flt(ps_item_qty[item['item_code']]) * no_of_cases)
-
-			elif event=='cancel':
-				new_packed_qty = flt(item['packed_qty']) - (flt(ps_item_qty[item['item_code']]) * no_of_cases)
-
+			new_packed_qty = flt(item['packed_qty'])
 			if (new_packed_qty < 0) or (new_packed_qty > flt(item['qty'])):
 				webnotes.msgprint("Invalid new packed quantity for item %s. \
 					Please try again or contact support@erpnext.com" % item['item_code'], raise_exception=1)
-
+			
+			delivery_note_item = webnotes.conn.get_value("Delivery Note Item", {
+				"parent": self.doc.delivery_note, "item_code": item["item_code"]})
+			
 			webnotes.conn.sql("""\
 				UPDATE `tabDelivery Note Item`
 				SET packed_qty = %s
 				WHERE parent = %s AND item_code = %s""",
-				(new_packed_qty, self.doc.delivery_note, item['item_code']))			
+				(new_packed_qty, self.doc.delivery_note, item['item_code']))
+			webnotes.conn.set_value("Delivery Note", self.doc.delivery_note,
+				"modified", now())
 
 
 	def update_item_details(self):
 		"""
 			Fill empty columns in Packing Slip Item
 		"""
-		self.doc.from_case_no = self.get_recommended_case_no()
+		if not self.doc.from_case_no:
+			self.doc.from_case_no = self.get_recommended_case_no()
 
 		from webnotes.model.code import get_obj
 		for d in self.doclist:
diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py
index 04ad4dc..9e23c27 100644
--- a/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -64,10 +64,6 @@
 							doc.fields[r] = ret[r]
 
 
-	# Get UOM Details
-	def get_uom_details(self, arg = ''):
-		return get_obj(dt='Purchase Common').get_uom_details(arg)
-
 	# GET TERMS & CONDITIONS
 	# =====================================================================================
 	def get_tc_details(self):
diff --git a/utilities/page/question_view/question_view.py b/utilities/page/question_view/question_view.py
index e79a808..175a8ed 100644
--- a/utilities/page/question_view/question_view.py
+++ b/utilities/page/question_view/question_view.py
@@ -19,8 +19,8 @@
 from webnotes.utils import load_json, cstr, now
 
 @webnotes.whitelist()
-def update_item(args):
-	args = load_json(args)
+def update_item(arg):
+	args = load_json(arg)
 	
 	webnotes.conn.sql("update `tab%s` set `%s`=%s, modified=%s where name=%s" \
 		% (args['dt'], args['fn'], '%s', '%s', '%s'), (args['text'], now(), args['dn']))
diff --git a/utilities/page/users/__init__.py b/utilities/page/users/__init__.py
deleted file mode 100644
index baffc48..0000000
--- a/utilities/page/users/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from __future__ import unicode_literals
diff --git a/utilities/page/users/users.css b/utilities/page/users/users.css
deleted file mode 100644
index b739a57..0000000
--- a/utilities/page/users/users.css
+++ /dev/null
@@ -1,46 +0,0 @@
-.user-card {
-	border-radius: 5px;
-	width: 200px;
-	margin: 11px;
-	padding: 11px;
-	background-color: #FFEDBD;
-	box-shadow: 3px 3px 5px #888;
-	float: left;
-	overflow: hidden;
-}
-
-.user-card.disabled {
-	background-color: #eee;
-}
-
-.user-card img {
-	height: 60px;
-}
-
-.user-role {
-	padding: 5px;
-	width: 45%;
-	float: left;
-}
-
-table.user-perm {
-	border-collapse: collapse;
-}
-
-table.user-perm td, table.user-perm th {
-	padding: 5px;
-	text-align: center;
-	border-bottom: 1px solid #aaa;
-	min-width: 30px;
-}
-
-.subscription-info-box {
-	margin: 0px 11px;
-	background-color: #EEEEEE;
-    border: 1px solid #DDDBDB;
-    padding: 5px 3px;
-}
-
-.subscription-info {
-	padding: 0px 10px;
-}
\ No newline at end of file
diff --git a/utilities/page/users/users.html b/utilities/page/users/users.html
deleted file mode 100644
index e69de29..0000000
--- a/utilities/page/users/users.html
+++ /dev/null
diff --git a/utilities/page/users/users.js b/utilities/page/users/users.js
deleted file mode 100644
index d09b207..0000000
--- a/utilities/page/users/users.js
+++ /dev/null
@@ -1,415 +0,0 @@
-// 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/>.
-
-$.extend(wn.pages.users, {
-	onload: function(wrapper) {
-		var w = wn.pages.users;
-		wn.ui.make_app_page({
-			parent: w,
-			title: "Users",
-			single_column: true
-		});
-		w.profiles = {};
-		w.refresh();
-		w.setup();
-		w.role_editor = new erpnext.RoleEditor();
-	},
-	setup: function() {
-		wn.pages.users.appframe.add_button('+ Add User', function() {
-			wn.pages.users.add_user();
-		});
-		
-		// set roles
-		var w = wn.pages.users;
-		$(w).on('click', '.btn.user-roles', function() {
-			var uid = $(this).parent().parent().attr('data-name');
-			wn.pages.users.role_editor.show(uid);
-		});
-
-		// settings
-		$(w).on('click', '.btn.user-settings', function() {
-			var uid = $(this).parent().parent().attr('data-name');
-			wn.pages.users.show_settings(uid);
-		});
-		
-		// delete
-		$(w).on('click', 'a.close', function() {
-			$card = $(this).parent();
-			var uid = $card.attr('data-name');
-			$card.css('opacity', 0.6);
-			wn.call({
-				method: 'utilities.page.users.users.delete',
-				args: {'uid': uid},
-				callback: function(r,rt) {
-					if(!r.exc)
-						$card.fadeOut()
-				}
-			});
-		})
-		
-	},
-	refresh: function() {
-		// make the list
-		wn.call({
-			method:'utilities.page.users.users.get',
-			callback: function(r, rt) {
-				$(wn.pages.users).find('.layout-main').empty();
-				for(var i in r.message) {
-					var p = r.message[i];
-					wn.pages.users.profiles[p.name] = p;
-					wn.pages.users.render(p);
-				}
-			}
-		});
-		if(!$('.subscription-info').length && (wn.boot.max_users || wn.boot.expires_on)) {
-			var $sub_info = $('<div class="subscription-info-box"><div>')
-					.insertAfter($(wn.pages.users).find('.help'));
-			if(wn.boot.max_users) {
-				$sub_info.append(repl('\
-				<span class="subscription-info"> \
-					Max Users: <b>%(max_users)s</b> \
-				</span>', { max_users: wn.boot.max_users }));
-			}
-			if(wn.boot.expires_on) {
-				$sub_info.append(repl('\
-				<span class="subscription-info"> \
-				Expires On: <b>%(expires_on)s</b> \
-				</span>', { expires_on: dateutil.str_to_user(wn.boot.expires_on) }));
-			}
-		}
-	},
-	render: function(data) {
-		if(data.file_list) {
-			data.imgsrc = 'files/' + data.file_list.split('\n')[0].split(',')[1];
-		} else {
-			data.imgsrc = 'lib/images/ui/no_img_' + (data.gender=='Female' ? 'f' : 'm') + '.gif';
-		}
-		data.fullname = wn.user_info(data.name).fullname;
-		data.delete_html = '';
-		if(!data.enabled) 
-			data.delete_html = '<a class="close" title="delete">&times;</a>';
-		
-		$(wn.pages.users).find('.layout-main').append(repl('<div class="user-card" data-name="%(name)s">\
-			%(delete_html)s\
-			<img src="%(imgsrc)s">\
-			<div class="user-info">\
-				<b class="user-fullname">%(fullname)s</b><br>\
-				%(name)s<br>\
-				<button class="btn btn-small user-roles"><i class="icon-user"></i> Roles</button>\
-				<button class="btn btn-small user-settings"><i class="icon-cog"></i> Settings</button>\
-			</div>\
-		</div>', data));
-		
-		if(!data.enabled) {
-			$(wn.pages.users).find('.layout-main .user-card:last')
-				.addClass('disabled')
-				.find('.user-fullname').html('Disabled');
-		}
-	},
-	show_settings: function(uid) {
-		var me = wn.pages.users;
-		if(!me.settings_dialog)
-			me.make_settings_dialog();
-		
-		var p = me.profiles[uid];
-		me.uid = uid;
-		
-		me.settings_dialog.set_values({
-			restrict_ip: p.restrict_ip || '',
-			login_before: p.login_before || '',
-			login_after: p.login_after || '',
-			enabled: p.enabled || 0,
-			new_password: ''
-		});
-		
-		me.settings_dialog.show();
-
-	},
-	make_settings_dialog: function() {
-		var me = wn.pages.users;
-		me.settings_dialog = new wn.ui.Dialog({
-			title: 'Set User Security',
-			width: 500,
-			fields: [
-				{
-					label:'Enabled',
-					description: 'Uncheck to disable',
-					fieldtype: 'Check', fieldname: 'enabled'
-				},
-				{
-					label:'IP Address', 
-					description: 'Restrict user login by IP address, partial ips (111.111.111), \
-					multiple addresses (separated by commas) allowed', 
-					fieldname:'restrict_ip', fieldtype:'Data'
-				},
-				{
-					label:'Login After',
-					description: 'User can only login after this hour (0-24)',
-					fieldtype: 'Int', fieldname: 'login_after'
-				},
-				{
-					label:'Login Before',
-					description: 'User can only login before this hour (0-24)',
-					fieldtype: 'Int', fieldname: 'login_before'
-				},
-				{
-					label:'New Password',
-					description: 'Update the current user password',
-					fieldtype: 'Data', fieldname: 'new_password'
-				},
-				{
-					label:'Update', fieldtype:'Button', fieldname:'update'
-				}
-			]
-		});
-
-		this.settings_dialog.fields_dict.update.input.onclick = function() {
-			var btn = this;
-			var args = me.settings_dialog.get_values();
-			args.user = me.uid;
-
-			if (args.new_password) {
-				me.get_password(btn, args);
-			} else {
-				me.update_security(btn, args);
-			}
-		};
-		
-	},
-	update_security: function(btn, args) {
-		var me = wn.pages.users;
-		$(btn).set_working();
-		$c_page('utilities', 'users', 'update_security', JSON.stringify(args), function(r,rt) {
-			$(btn).done_working();
-			if(r.exc) {
-				msgprint(r.exc);				
-				return;
-			}
-			me.settings_dialog.hide();
-			$.extend(me.profiles[me.uid], me.settings_dialog.get_values());
-			me.refresh();
-		});
-	},
-	get_password: function(btn, args) {
-		var me = wn.pages.users;
-		var pass_d = new wn.ui.Dialog({
-			title: 'Your Password',
-			width: 300,
-			fields: [
-				{
-					label: 'Please Enter <b style="color: black">Your Password</b>',
-					description: "Your password is required to update the user's password",
-					fieldtype: 'Password', fieldname: 'sys_admin_pwd', reqd: 1		
-				},
-				{
-					label: 'Continue', fieldtype: 'Button', fieldname: 'continue'
-				}
-			]
-		});
-
-		pass_d.fields_dict.continue.input.onclick = function() {
-			btn.pwd_dialog.hide();					
-			args.sys_admin_pwd = btn.pwd_dialog.get_values().sys_admin_pwd;					
-			btn.set_working();					
-			me.update_security(btn, args);
-			btn.done_working();
-		}
-
-		pass_d.show();
-		btn.pwd_dialog = pass_d;
-		btn.done_working();	
-	},
-	add_user: function() {
-		var me = wn.pages.users;
-		var active_users = $('.user-card:not(.disabled)');
-		if(wn.boot.max_users && (active_users.length >= wn.boot.max_users)) {
-			msgprint(repl("You already have <b>%(active_users)s</b> active users, \
-			which is the maximum number that you are currently allowed to add. <br /><br /> \
-			So, to add more users, you can:<br /> \
-			1. <b>Upgrade to the unlimited users plan</b>, or<br /> \
-			2. <b>Disable one or more of your existing users and try again</b>",
-				{active_users: active_users.length}));
-			return;
-		}
-		var d = new wn.ui.Dialog({
-			title: 'Add User',
-			width: 400,
-			fields: [{
-					fieldtype: 'Data', fieldname: 'user', reqd: 1, 
-					label: 'Email Id of the user to add'
-				}, {
-					fieldtype: 'Data', fieldname: 'first_name', reqd: 1, label: 'First Name'
-				}, {
-					fieldtype: 'Data', fieldname: 'last_name', label: 'Last Name'
-				}, {
-					fieldtype: 'Data', fieldname: 'password', reqd: 1, label: 'Password'
-				}, {
-					fieldtype: 'Button', label: 'Add', fieldname: 'add'
-				}]
-		});
-		
-		d.make();
-		d.fields_dict.add.input.onclick = function() {
-			v = d.get_values();
-			if(v) {
-				d.fields_dict.add.input.set_working();
-				$c_page('utilities', 'users', 'add_user', v, function(r,rt) {
-					if(r.exc) { msgprint(r.exc); return; }
-					else {
-						wn.boot.user_info[v.user] = {fullname:v.first_name + ' ' + (v.last_name || '')};
-						d.hide();
-						me.refresh();
-					}
-				})
-			}
-		}
-		d.show();		
-	}
-});
-
-erpnext.RoleEditor = Class.extend({
-	init: function() {
-		this.dialog = new wn.ui.Dialog({
-			title: 'Set Roles'
-		});
-		var me = this;
-		$(this.dialog.body).html('<div class="help">Loading...</div>')
-		wn.call({
-			method:'utilities.page.users.users.get_roles',
-			callback: function(r) {
-				me.roles = r.message;
-				me.show_roles();
-			}
-		});
-	},
-	show_roles: function() {
-		var me = this;
-		$(this.dialog.body).empty();
-		for(var i in this.roles) {
-			$(this.dialog.body).append(repl('<div class="user-role" \
-				data-user-role="%(role)s">\
-				<input type="checkbox"> \
-				<a href="#"><i class="icon-question-sign"></i></a> %(role)s\
-			</div>', {role: this.roles[i]}));
-		}
-		$(this.dialog.body).append('<div style="clear: both">\
-			<button class="btn btn-small btn-info">Save</button></div>');
-		$(this.dialog.body).find('button.btn-info').click(function() {
-			me.save();
-		});
-		$(this.dialog.body).find('.user-role a').click(function() {
-			me.show_permissions($(this).parent().attr('data-user-role'))
-			return false;
-		})
-	},
-	show: function(uid) {
-		var me = this;
-		this.uid = uid;
-		this.dialog.show();
-		// set user roles
-		wn.call({
-			method:'utilities.page.users.users.get_user_roles',
-			args: {uid:uid},
-			callback: function(r, rt) {
-				$(me.dialog.body).find('input[type="checkbox"]').attr('checked', false);
-				for(var i in r.message) {
-					$(me.dialog.body)
-						.find('[data-user-role="'+r.message[i]
-							+'"] input[type="checkbox"]').attr('checked',true);
-				}
-			}
-		})
-	},
-	save: function() {
-		var set_roles = [];
-		var unset_roles = [];
-		$(this.dialog.body).find('[data-user-role]').each(function() {
-			var $check = $(this).find('input[type="checkbox"]');
-			if($check.attr('checked')) {
-				set_roles.push($(this).attr('data-user-role'));
-			} else {
-				unset_roles.push($(this).attr('data-user-role'));
-			}
-		})
-		wn.call({
-			method:'utilities.page.users.users.update_roles',
-			args: {
-				set_roles: JSON.stringify(set_roles),
-				unset_roles: JSON.stringify(unset_roles),
-				uid: this.uid
-			},
-			btn: $(this.dialog.body).find('.btn-info').get(0),
-			callback: function() {
-				
-			}
-		})
-	},
-	show_permissions: function(role) {
-		// show permissions for a role
-		var me = this;
-		if(!this.perm_dialog)
-			this.make_perm_dialog()
-		$(this.perm_dialog.body).empty();
-		wn.call({
-			method:'utilities.page.users.users.get_perm_info',
-			args: {role: role},
-			callback: function(r) {
-				var $body = $(me.perm_dialog.body);
-				$body.append('<table class="user-perm"><tbody><tr>\
-					<th style="text-align: left">Document Type</th>\
-					<th>Level</th>\
-					<th>Read</th>\
-					<th>Write</th>\
-					<th>Submit</th>\
-					<th>Cancel</th>\
-					<th>Amend</th></tr></tbody></table>');
-				for(var i in r.message) {
-					var perm = r.message[i];
-					
-					// if permission -> icon
-					for(key in perm) {
-						if(key!='parent' && key!='permlevel') {
-							if(perm[key]) {
-								perm[key] = '<i class="icon-ok"></i>';
-							} else {
-								perm[key] = '';
-							}							
-						}
-					}
-					
-					$body.find('tbody').append(repl('<tr>\
-						<td style="text-align: left">%(parent)s</td>\
-						<td>%(permlevel)s</td>\
-						<td>%(read)s</td>\
-						<td>%(write)s</td>\
-						<td>%(submit)s</td>\
-						<td>%(cancel)s</td>\
-						<td>%(amend)s</td>\
-						</tr>', perm))
-				}
-				
-				me.perm_dialog.show();
-			}
-		});
-		
-	},
-	make_perm_dialog: function() {
-		this.perm_dialog = new wn.ui.Dialog({
-			title:'Role Permissions',
-			width: 500
-		});
-	}
-})
diff --git a/utilities/page/users/users.py b/utilities/page/users/users.py
deleted file mode 100644
index 9878d3c..0000000
--- a/utilities/page/users/users.py
+++ /dev/null
@@ -1,202 +0,0 @@
-# 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/>.
-
-from __future__ import unicode_literals
-import webnotes
-import json
-
-from webnotes.model.doc import Document
-from webnotes.utils import cint
-
-@webnotes.whitelist()
-def get(arg=None):
-	"""return all users"""
-	return webnotes.conn.sql("""select name, file_list, enabled, gender,
-	 	restrict_ip, login_before, login_after from tabProfile
-		where docstatus<2 and name not in ('Administrator', 'Guest') order by
-		ifnull(enabled,0) desc, name""", as_dict=1)
-
-@webnotes.whitelist()
-def get_roles(arg=None):
-	"""return all roles except standard"""
-	return _get_roles(webnotes.form_dict['uid'])
-
-def _get_roles(user):
-	"""return all roles except standard"""
-	return [r[0] for r in webnotes.conn.sql("""select name from tabRole
-		where name not in ('Administrator', 'Guest', 'All') order by name""", user)]
-
-@webnotes.whitelist()
-def get_user_roles(arg=None):
-	"""get roles for a user"""
-	return [r[0] for r in webnotes.conn.sql("""select role from tabUserRole
-		where parent=%s""", webnotes.form_dict['uid'])]
-
-@webnotes.whitelist()
-def get_perm_info(arg=None):
-	"""get permission info"""
-	return webnotes.conn.sql("""select parent, permlevel, `read`, `write`, submit,
-		cancel, amend from tabDocPerm where role=%s 
-		and docstatus<2 order by parent, permlevel""", 
-			webnotes.form_dict['role'], as_dict=1)
-
-@webnotes.whitelist()
-def update_roles(arg=None):
-	"""update set and unset roles"""
-	# remove roles
-	unset = json.loads(webnotes.form_dict['unset_roles'])
-	webnotes.conn.sql("""delete from tabUserRole where parent='%s' 
-		and role in ('%s')""" % (webnotes.form_dict['uid'], "','".join(unset)))
-
-	# check for 1 system manager
-	if not webnotes.conn.sql("""select parent from tabUserRole where role='System Manager'
-		and docstatus<2"""):
-		webnotes.msgprint("Sorry there must be atleast one 'System Manager'")
-		raise webnotes.ValidationError
-
-	# add roles
-	roles = get_user_roles()
-	toset = json.loads(webnotes.form_dict['set_roles'])
-	for role in toset:
-		if not role in roles:
-			d = Document('UserRole')
-			d.role = role
-			d.parent = webnotes.form_dict['uid']
-			d.save()
-	
-	webnotes.msgprint('Roles Updated')
-
-@webnotes.whitelist()
-def update_security(args=''):
-	args = json.loads(args)
-	webnotes.conn.set_value('Profile', args['user'], 'restrict_ip', args.get('restrict_ip') or '')
-	webnotes.conn.set_value('Profile', args['user'], 'login_after', args.get('login_after') or None)
-	webnotes.conn.set_value('Profile', args['user'], 'login_before', args.get('login_before') or None)
-	webnotes.conn.set_value('Profile', args['user'], 'enabled', int(args.get('enabled',0)) or 0)
-	
-	# logout a disabled user
-	if not int(args.get('enabled',0) or 0):
-		webnotes.login_manager.logout(user=args['user'])
-
-	if args.get('new_password') and args.get('sys_admin_pwd'):
-		from webnotes.utils import cint
-		webnotes.conn.sql("update tabProfile set password=password(%s) where name=%s", 
-			(args['new_password'], args['user']))
-	else: 
-		webnotes.msgprint('Settings Updated')
-
-
-
-#
-# user addition
-#
-
-@webnotes.whitelist()
-def add_user(args):
-	args = json.loads(args)
-	add_profile(args)
-	
-@webnotes.whitelist()
-def add_profile(args):
-	from webnotes.utils import validate_email_add, now
-	email = args['user']		
-	sql = webnotes.conn.sql
-		
-	# validate max number of users exceeded or not
-	import conf
-	if hasattr(conf, 'max_users'):
-		active_users = sql("""select count(*) from tabProfile
-			where ifnull(enabled, 0)=1 and docstatus<2
-			and name not in ('Administrator', 'Guest')""")[0][0]
-		if active_users >= conf.max_users and conf.max_users:
-			# same message as in users.js
-			webnotes.msgprint("""Alas! <br />\
-				You already have <b>%(active_users)s</b> active users, \
-				which is the maximum number that you are currently allowed to add. <br /><br /> \
-				So, to add more users, you can:<br /> \
-				1. <b>Upgrade to the unlimited users plan</b>, or<br /> \
-				2. <b>Disable one or more of your existing users and try again</b>""" \
-				% {'active_users': active_users}, raise_exception=1)
-	
-	if not email:
-		email = webnotes.form_dict.get('user')
-	if not validate_email_add(email):
-		raise Exception
-		return 'Invalid Email Id'
-	
-	if sql("select name from tabProfile where name = %s", email):
-		# exists, enable it
-		sql("update tabProfile set enabled = 1, docstatus=0 where name = %s", email)
-		webnotes.msgprint('Profile exists, enabled it with new password')
-	else:
-		# does not exist, create it!
-		pr = Document('Profile')
-		pr.name = email
-		pr.email = email
-		pr.first_name = args.get('first_name')
-		pr.last_name = args.get('last_name')
-		pr.enabled = 1
-		pr.user_type = 'System User'
-		pr.save(1)
-
-	if args.get('password'):
-		sql("""
-			UPDATE tabProfile 
-			SET password = PASSWORD(%s), modified = %s
-			WHERE name = %s""", (args.get('password'), now, email))
-
-	send_welcome_mail(email, args)
-
-@webnotes.whitelist()
-def send_welcome_mail(email, args):
-	"""send welcome mail to user with password and login url"""
-	pr = Document('Profile', email)
-	from webnotes.utils.email_lib import sendmail_md
-	args.update({
-		'company': webnotes.conn.get_default('company'),
-		'password': args.get('password'),
-		'account_url': webnotes.conn.get_value('Website Settings',
-			'Website Settings', 'subdomain') or ""
-	})
-	if not args.get('last_name'): args['last_name'] = ''
-	sendmail_md(pr.email, subject="Welcome to ERPNext", msg=welcome_txt % args)
-
-#
-# delete user
-#
-@webnotes.whitelist()
-def delete(arg=None):
-	"""delete user"""
-	webnotes.conn.sql("update tabProfile set enabled=0, docstatus=2 where name=%s", 
-		webnotes.form_dict['uid'])
-	webnotes.login_manager.logout(user=webnotes.form_dict['uid'])
-	
-welcome_txt = """
-## %(company)s
-
-Dear %(first_name)s %(last_name)s
-
-Welcome!
-
-A new account has been created for you, here are your details:
-
-login-id: %(user)s
-password: %(password)s
-
-To login to your new ERPNext account, please go to:
-
-%(account_url)s
-"""
diff --git a/utilities/page/users/users.txt b/utilities/page/users/users.txt
deleted file mode 100644
index 165cc16..0000000
--- a/utilities/page/users/users.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-# Page, users
-[
-
-	# These values are common in all dictionaries
-	{
-		'creation': '2012-02-28 10:29:39',
-		'docstatus': 0,
-		'modified': '2012-02-28 10:29:39',
-		'modified_by': u'Administrator',
-		'owner': u'Administrator'
-	},
-
-	# These values are common for all Page
-	{
-		'doctype': 'Page',
-		'module': u'Utilities',
-		'name': '__common__',
-		'page_name': u'users',
-		'standard': u'Yes',
-		'title': u'Users'
-	},
-
-	# Page, users
-	{
-		'doctype': 'Page',
-		'name': u'users'
-	}
-]
\ No newline at end of file