Merge branch 'master' into slow
diff --git a/accounts/doctype/account/account.py b/accounts/doctype/account/account.py
index 410994f..eb65604 100644
--- a/accounts/doctype/account/account.py
+++ b/accounts/doctype/account/account.py
@@ -69,11 +69,13 @@
 				raise_exception=1)
 	
 	def validate_duplicate_account(self):
-		if (self.doc.fields.get('__islocal') or not self.doc.name) and \
-				sql("""select name from tabAccount where account_name=%s and company=%s""", 
-					(self.doc.account_name, self.doc.company)):
-			msgprint("Account Name: %s already exists, please rename" 
-				% self.doc.account_name, raise_exception=1)
+		
+		if self.doc.fields.get('__islocal') or not self.doc.name:
+			company_abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr")
+			if sql("""select name from tabAccount where name=%s""", 
+				(self.doc.account_name + " - " + company_abbr)):
+					msgprint("Account Name: %s already exists, please rename" 
+						% self.doc.account_name, raise_exception=1)
 				
 	def validate_root_details(self):
 		#does not exists parent
diff --git a/accounts/page/general_ledger/general_ledger.js b/accounts/page/general_ledger/general_ledger.js
index 4a3f21e..21be3a0 100644
--- a/accounts/page/general_ledger/general_ledger.js
+++ b/accounts/page/general_ledger/general_ledger.js
@@ -306,13 +306,11 @@
 	},
 
 	make_account_by_name: function() {
-		if(!this.account_by_name) {
-			this.account_by_name = this.make_name_map(wn.report_dump.data["Account"]);
-			this.make_voucher_acconuts_map();
-		}
+		this.account_by_name = this.make_name_map(wn.report_dump.data["Account"]);
+		this.make_voucher_accounts_map();
 	},
 	
-	make_voucher_acconuts_map: function() {
+	make_voucher_accounts_map: function() {
 		this.voucher_accounts = {};
 		var data = wn.report_dump.data["GL Entry"];
 		for(var i=0, j=data.length; i<j; i++) {
diff --git a/home/page/latest_updates/latest_updates.js b/home/page/latest_updates/latest_updates.js
index c0bad94..949849d 100644
--- a/home/page/latest_updates/latest_updates.js
+++ b/home/page/latest_updates/latest_updates.js
@@ -1,4 +1,5 @@
 erpnext.updates = [
+	["12th April", ["Employee: List of Leave Approvers who can approve the Employee's Leave Applications"]],
 	["27th March", ["Rename multiple items together. Go to Setup > Rename Tool"]],
 	["26th March", ["Added project to Stock Ledger and Balance",
 		"Added Default Cash Account in Company."]],
diff --git a/hr/doctype/employee/employee.js b/hr/doctype/employee/employee.js
index 239b3b7..5a2dbab 100644
--- a/hr/doctype/employee/employee.js
+++ b/hr/doctype/employee/employee.js
@@ -14,62 +14,95 @@
 // You should have received a copy of the GNU General Public License
 // along with this program.	If not, see <http://www.gnu.org/licenses/>.
 
-cur_frm.cscript.onload = function(doc) {
-	// bc
-	var india_specific = ["esic_card_no", "gratuity_lic_id", "pan_number", "pf_number"]
-	if(wn.control_panel.country!="India") {
-		hide_field(india_specific);
-	}
-}
-
-cur_frm.cscript.refresh = function(doc) {
-	if(!doc.__islocal) {
-		hide_field("naming_series");
-		cur_frm.add_custom_button('Make Salary Structure', 
-			cur_frm.cscript['Make Salary Structure']);
-	}
-}
-
-cur_frm.cscript.date_of_birth = function(doc, dt, dn) {
-	get_server_fields('get_retirement_date','','',doc,dt,dn,1);
-}
-
-cur_frm.cscript.salutation = function(doc,dt,dn) {
-	if(doc.salutation){
-		if(doc.salutation=='Mr')
-			doc.gender='Male';
-		else if(doc.salutation=='Ms')
-			doc.gender='Female';
-		refresh_field('gender');
-	}
-}
-
-cur_frm.cscript['Make Salary Structure']=function(){
-	$c_obj(make_doclist (cur_frm.doc.doctype, cur_frm.doc.name), 'check_sal_structure',
-	 	cur_frm.doc.name, function(r, rt) {
-			if(r.message)
-				msgprint("You have already created Active salary structure.\n \
-					If you want to create new one, please ensure that no active salary structure \
-					 exist.\nTo inactive salary structure select 'Is Active' as 'No'.");
-			else
-				cur_frm.cscript.make_salary_structure(cur_frm.doc); 
+wn.provide("erpnext.hr");
+erpnext.hr.EmployeeController = wn.ui.form.Controller.extend({
+	setup: function() {
+		this.setup_leave_approver_select();
+		this.frm.fields_dict.user_id.get_query = erpnext.utils.profile_query;
+		this.frm.fields_dict.reports_to.get_query = erpnext.utils.employee_query;
+	},
+	
+	onload: function() {
+		this.frm.toggle_display(["esic_card_no", "gratuity_lic_id", "pan_number", "pf_number"],
+			wn.control_panel.country==="India");
+	},
+	
+	refresh: function() {
+		var me = this;
+		erpnext.hide_naming_series();
+		if(!this.frm.doc.__islocal) {
+			cur_frm.add_custom_button('View Active Salary Structure', function() {
+				me.view_active_salary_structure(this); });
+			
+			cur_frm.add_custom_button('Make Salary Structure', function() {
+				me.make_salary_structure(this); });
+			
 		}
-	);
-}
-
-cur_frm.cscript.make_salary_structure = function(doc, dt, dn, det){
-	var st = wn.model.make_new_doc_and_get_name('Salary Structure');
-	st = locals['Salary Structure'][st];
-	st.employee = doc.name;
-	st.employee_name = doc.employee_name;
-	st.branch=doc.branch;
-	st.designation=doc.designation;
-	st.department=doc.department;
-	st.fiscal_year = doc.fiscal_year
-	st.grade=doc.grade;
-	loaddoc('Salary Structure', st.name);
-}
-
-cur_frm.fields_dict.user_id.get_query = erpnext.utils.profile_query;
-
-cur_frm.fields_dict.reports_to.get_query = erpnext.utils.employee_query;
\ No newline at end of file
+	},
+	
+	setup_leave_approver_select: function() {
+		var me = this;
+		this.frm.call({
+			method:"hr.utils.get_leave_approver_list",
+			callback: function(r) {
+				me.frm.fields_dict.employee_leave_approvers.grid.get_field("leave_approver").df.options =
+					$.map(r.message, function(profile) { 
+						return {value: profile, label: wn.user_info(profile).fullname}; 
+					});
+			}
+		});
+	},
+	
+	date_of_birth: function() {
+		cur_frm.call({
+			method: "get_retirement_date",
+			args: {date_of_birth: this.frm.doc.date_of_birth}
+		});
+	},
+	
+	salutation: function() {
+		if(this.frm.doc.salutation) {
+			this.frm.set_value("gender", {
+				"Mr": "Male",
+				"Ms": "Female"
+			}[this.frm.doc.salutation]);
+		}
+	},
+	
+	make_salary_structure: function(btn) {
+		var me = this;
+		this.validate_salary_structure(btn, function(r) {
+			if(r.message) {
+				msgprint(wn._("Employee") + ' "' + me.frm.doc.name + '": ' 
+					+ wn._("An active Salary Structure already exists. \
+						If you want to create new one, please ensure that no active Salary Structure \
+					 	exists for this Employee. Go to the active Salary Structure and set \
+						\"Is Active\" = \"No\""));
+			} else if(!r.exc) {
+				wn.model.map({
+					source: wn.model.get_doclist(me.frm.doc.doctype, me.frm.doc.name),
+					target: "Salary Structure"
+				});
+			}
+		});
+	},
+	
+	validate_salary_structure: function(btn, callback) {
+		var me = this;
+		this.frm.call({
+			btn: btn,
+			method: "webnotes.client.get_value",
+			args: {
+				doctype: "Salary Structure",
+				fieldname: "name",
+				filters: {
+					employee: me.frm.doc.name,
+					is_active: "Yes",
+					docstatus: ["!=", 2]
+				},
+			},
+			callback: callback
+		});
+	},
+});
+cur_frm.cscript = new erpnext.hr.EmployeeController({frm: cur_frm});
\ No newline at end of file
diff --git a/hr/doctype/employee/employee.py b/hr/doctype/employee/employee.py
index 16ecb6d..59c8380 100644
--- a/hr/doctype/employee/employee.py
+++ b/hr/doctype/employee/employee.py
@@ -27,7 +27,7 @@
 	def __init__(self,doc,doclist=[]):
 		self.doc = doc
 		self.doclist = doclist
-
+		
 	def autoname(self):
 		ret = sql("select value from `tabSingles` where doctype = 'Global Defaults' and field = 'emp_created_by'")
 		if not ret:
@@ -49,30 +49,31 @@
 		self.validate_email()
 		self.validate_name()
 		self.validate_status()
-				
-	def get_retirement_date(self):		
-		import datetime
-		ret = {}
-		if self.doc.date_of_birth:
-			dt = getdate(self.doc.date_of_birth) + datetime.timedelta(21915)
-			ret = {'date_of_retirement': dt.strftime('%Y-%m-%d')}
-		return ret
-
-	def check_sal_structure(self, nm):
-		ret_sal_struct=sql("select name from `tabSalary Structure` where employee='%s' and is_active = 'Yes' and docstatus!= 2"%nm)
-		return ret_sal_struct and ret_sal_struct[0][0] or ''
-
+		self.validate_employee_leave_approver()
+		
 	def on_update(self):
 		if self.doc.user_id:
 			self.update_user_default()
 			self.update_profile()
-	
+				
 	def update_user_default(self):
 		webnotes.conn.set_default("employee", self.doc.name, self.doc.user_id)
 		webnotes.conn.set_default("employee_name", self.doc.employee_name, self.doc.user_id)
 		webnotes.conn.set_default("company", self.doc.company, self.doc.user_id)
-		if self.doc.reports_to:
-			webnotes.conn.set_default("leave_approver", webnotes.conn.get_value("Employee", self.doc.reports_to, "user_id"), self.doc.user_id)
+		self.set_default_leave_approver()
+	
+	def set_default_leave_approver(self):
+		employee_leave_approvers = self.doclist.get({"parentfield": "employee_leave_approvers"})
+
+		if len(employee_leave_approvers):
+			webnotes.conn.set_default("leave_approver", employee_leave_approvers[0].leave_approver,
+				self.doc.user_id)
+		
+		elif self.doc.reports_to:
+			from webnotes.profile import Profile
+			reports_to_user = webnotes.conn.get_value("Employee", self.doc.reports_to, "user_id")
+			if "Leave Approver" in Profile(reports_to_user).get_roles():
+				webnotes.conn.set_default("leave_approver", reports_to_user, self.doc.user_id)
 
 	def update_profile(self):
 		# add employee role if missing
@@ -116,7 +117,6 @@
 		profile_wrapper.save()
 		
 	def validate_date(self):
-		import datetime
 		if self.doc.date_of_birth and self.doc.date_of_joining and getdate(self.doc.date_of_birth) >= getdate(self.doc.date_of_joining):
 			msgprint('Date of Joining must be greater than Date of Birth')
 			raise Exception
@@ -167,3 +167,21 @@
 		if self.doc.status == 'Left' and not self.doc.relieving_date:
 			msgprint("Please enter relieving date.")
 			raise Exception
+			
+	def validate_employee_leave_approver(self):
+		from webnotes.profile import Profile
+		from hr.doctype.leave_application.leave_application import InvalidLeaveApproverError
+		
+		for l in self.doclist.get({"parentfield": "employee_leave_approvers"}):
+			if "Leave Approver" not in Profile(l.leave_approver).get_roles():
+				msgprint(_("Invalid Leave Approver") + ": \"" + l.leave_approver + "\"",
+					raise_exception=InvalidLeaveApproverError)
+
+@webnotes.whitelist()
+def get_retirement_date(date_of_birth=None):
+	import datetime
+	ret = {}
+	if date_of_birth:
+		dt = getdate(date_of_birth) + datetime.timedelta(21915)
+		ret = {'date_of_retirement': dt.strftime('%Y-%m-%d')}
+	return ret
diff --git a/hr/doctype/employee/employee.txt b/hr/doctype/employee/employee.txt
index 7b1f730..997a1ef 100644
--- a/hr/doctype/employee/employee.txt
+++ b/hr/doctype/employee/employee.txt
@@ -1,8 +1,8 @@
 [
  {
-  "creation": "2013-01-23 19:57:17", 
+  "creation": "2013-03-07 09:04:18", 
   "docstatus": 0, 
-  "modified": "2013-02-08 13:07:25", 
+  "modified": "2013-04-12 07:16:42", 
   "modified_by": "Administrator", 
   "owner": "Administrator"
  }, 
@@ -323,15 +323,6 @@
   "reqd": 0
  }, 
  {
-  "doctype": "DocField", 
-  "fieldname": "reports_to", 
-  "fieldtype": "Link", 
-  "label": "Reports to", 
-  "oldfieldname": "reports_to", 
-  "oldfieldtype": "Link", 
-  "options": "Employee"
- }, 
- {
   "description": "Provide email id registered in company", 
   "doctype": "DocField", 
   "fieldname": "company_email", 
@@ -344,6 +335,14 @@
  }, 
  {
   "doctype": "DocField", 
+  "fieldname": "notice_number_of_days", 
+  "fieldtype": "Int", 
+  "label": "Notice - Number of Days", 
+  "oldfieldname": "notice_number_of_days", 
+  "oldfieldtype": "Int"
+ }, 
+ {
+  "doctype": "DocField", 
   "fieldname": "salary_information", 
   "fieldtype": "Column Break", 
   "label": "Salary Information", 
@@ -407,6 +406,29 @@
  }, 
  {
   "doctype": "DocField", 
+  "fieldname": "organization_profile", 
+  "fieldtype": "Section Break", 
+  "label": "Organization Profile"
+ }, 
+ {
+  "doctype": "DocField", 
+  "fieldname": "reports_to", 
+  "fieldtype": "Link", 
+  "label": "Reports to", 
+  "oldfieldname": "reports_to", 
+  "oldfieldtype": "Link", 
+  "options": "Employee"
+ }, 
+ {
+  "description": "The first Leave Approver in the list will be set as the default Leave Approver", 
+  "doctype": "DocField", 
+  "fieldname": "employee_leave_approvers", 
+  "fieldtype": "Table", 
+  "label": "Leave Approvers", 
+  "options": "Employee Leave Approver"
+ }, 
+ {
+  "doctype": "DocField", 
   "fieldname": "contact_details", 
   "fieldtype": "Section Break", 
   "label": "Contact Details"
@@ -431,14 +453,6 @@
  }, 
  {
   "doctype": "DocField", 
-  "fieldname": "notice_number_of_days", 
-  "fieldtype": "Int", 
-  "label": "Notice - Number of Days", 
-  "oldfieldname": "notice_number_of_days", 
-  "oldfieldtype": "Int"
- }, 
- {
-  "doctype": "DocField", 
   "fieldname": "emergency_contact_details", 
   "fieldtype": "HTML", 
   "label": "Emergency Contact Details", 
@@ -767,4 +781,4 @@
   "role": "HR Manager", 
   "write": 1
  }
-]
+]
\ No newline at end of file
diff --git a/hr/doctype/employee_leave_approver/__init__.py b/hr/doctype/employee_leave_approver/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hr/doctype/employee_leave_approver/__init__.py
diff --git a/hr/doctype/employee_leave_approver/employee_leave_approver.py b/hr/doctype/employee_leave_approver/employee_leave_approver.py
new file mode 100644
index 0000000..928aa9f
--- /dev/null
+++ b/hr/doctype/employee_leave_approver/employee_leave_approver.py
@@ -0,0 +1,8 @@
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+class DocType:
+	def __init__(self, d, dl):
+		self.doc, self.doclist = d, dl
\ No newline at end of file
diff --git a/hr/doctype/employee_leave_approver/employee_leave_approver.txt b/hr/doctype/employee_leave_approver/employee_leave_approver.txt
new file mode 100644
index 0000000..31e3e09
--- /dev/null
+++ b/hr/doctype/employee_leave_approver/employee_leave_approver.txt
@@ -0,0 +1,39 @@
+[
+ {
+  "creation": "2013-04-12 06:56:15", 
+  "docstatus": 0, 
+  "modified": "2013-04-12 07:53:33", 
+  "modified_by": "Administrator", 
+  "owner": "Administrator"
+ }, 
+ {
+  "allow_import": 0, 
+  "autoname": "LAPPR-/.#####", 
+  "description": "Users who can approve a specific employee's leave applications", 
+  "doctype": "DocType", 
+  "istable": 1, 
+  "module": "HR", 
+  "name": "__common__"
+ }, 
+ {
+  "doctype": "DocField", 
+  "fieldname": "leave_approver", 
+  "fieldtype": "Select", 
+  "label": "Leave Approver", 
+  "name": "__common__", 
+  "parent": "Employee Leave Approver", 
+  "parentfield": "fields", 
+  "parenttype": "DocType", 
+  "permlevel": 0, 
+  "print_hide": 1, 
+  "reqd": 1, 
+  "width": "200"
+ }, 
+ {
+  "doctype": "DocType", 
+  "name": "Employee Leave Approver"
+ }, 
+ {
+  "doctype": "DocField"
+ }
+]
\ No newline at end of file
diff --git a/hr/doctype/expense_claim/expense_claim.js b/hr/doctype/expense_claim/expense_claim.js
index 72fe15c..5b136d0 100644
--- a/hr/doctype/expense_claim/expense_claim.js
+++ b/hr/doctype/expense_claim/expense_claim.js
@@ -29,7 +29,7 @@
 	}
 
 	cur_frm.call({
-		method:"get_approver_list",
+		method:"hr.utils.get_expense_approver_list",
 		callback: function(r) {
 			cur_frm.set_df_property("exp_approver", "options", r.message);
 		}
diff --git a/hr/doctype/expense_claim/expense_claim.py b/hr/doctype/expense_claim/expense_claim.py
index 0aa9ed8..0564d1d 100644
--- a/hr/doctype/expense_claim/expense_claim.py
+++ b/hr/doctype/expense_claim/expense_claim.py
@@ -52,12 +52,3 @@
 		if not getlist(self.doclist, 'expense_voucher_details'):
 			msgprint("Please add expense voucher details")
 			raise Exception
-		
-@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/leave_application/leave_application.js b/hr/doctype/leave_application/leave_application.js
index 0252818..7f8948a 100755
--- a/hr/doctype/leave_application/leave_application.js
+++ b/hr/doctype/leave_application/leave_application.js
@@ -26,7 +26,7 @@
 	}
 	cur_frm.set_df_property("leave_approver", "options", "");
 	cur_frm.call({
-		method:"get_approver_list",
+		method:"hr.utils.get_leave_approver_list",
 		callback: function(r) {
 			cur_frm.set_df_property("leave_approver", "options", $.map(r.message, 
 				function(profile) { 
diff --git a/hr/doctype/leave_application/leave_application.py b/hr/doctype/leave_application/leave_application.py
index d34abd8..b9f9e5b 100755
--- a/hr/doctype/leave_application/leave_application.py
+++ b/hr/doctype/leave_application/leave_application.py
@@ -18,11 +18,13 @@
 import webnotes
 from webnotes import _
 
-from webnotes.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_url_to_form
+from webnotes.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_url_to_form, \
+	comma_or, get_fullname
 from webnotes import msgprint
 
-class LeaveDayBlockedError(Exception): pass
-class OverlapError(Exception): pass
+class LeaveDayBlockedError(webnotes.ValidationError): pass
+class OverlapError(webnotes.ValidationError): pass
+class InvalidLeaveApproverError(webnotes.ValidationError): pass
 	
 from webnotes.model.controller import DocListController
 class DocType(DocListController):
@@ -39,6 +41,7 @@
 		self.validate_max_days()
 		self.show_block_day_warning()
 		self.validate_block_days()
+		self.validate_leave_approver()
 		
 	def on_update(self):
 		if (not self.previous_doc and self.doc.leave_approver) or (self.previous_doc and \
@@ -156,6 +159,21 @@
 			msgprint("Sorry ! You cannot apply for %s for more than %s days" % (self.doc.leave_type, max_days))
 			raise Exception
 			
+	def validate_leave_approver(self):
+		employee = webnotes.bean("Employee", self.doc.employee)
+		leave_approvers = [l.leave_approver for l in 
+			employee.doclist.get({"parentfield": "employee_leave_approvers"})]
+
+		if len(leave_approvers) and self.doc.leave_approver not in leave_approvers:
+			msgprint(("[" + _("For Employee") + ' "' + self.doc.employee + '"] ' 
+				+ _("Leave Approver can be one of") + ": "
+				+ comma_or(leave_approvers)), raise_exception=InvalidLeaveApproverError)
+		
+		elif self.doc.leave_approver and not webnotes.conn.sql("""select name from `tabUserRole` 
+			where parent=%s and role='Leave Approver'""", self.doc.leave_approver):
+				msgprint(get_fullname(self.doc.leave_approver) + ": " \
+					+ _("does not have role 'Leave Approver'"), raise_exception=InvalidLeaveApproverError)
+			
 	def notify_employee(self, status):
 		employee = webnotes.doc("Employee", self.doc.employee)
 		if not employee.user_id:
@@ -221,15 +239,6 @@
 	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
-
 def is_lwp(leave_type):
 	lwp = webnotes.conn.sql("select is_lwp from `tabLeave Type` where name = %s", leave_type)
 	return lwp and cint(lwp[0][0]) or 0
diff --git a/hr/doctype/leave_application/test_leave_application.py b/hr/doctype/leave_application/test_leave_application.py
index 672e668..338225c 100644
--- a/hr/doctype/leave_application/test_leave_application.py
+++ b/hr/doctype/leave_application/test_leave_application.py
@@ -4,6 +4,23 @@
 from hr.doctype.leave_application.leave_application import LeaveDayBlockedError, OverlapError
 
 class TestLeaveApplication(unittest.TestCase):
+	def _clear_roles(self):
+		webnotes.conn.sql("""delete from `tabUserRole` where parent in 
+			("test@example.com", "test1@example.com", "test2@example.com")""")
+			
+	def _clear_applications(self):
+		webnotes.conn.sql("""delete from `tabLeave Application`""")
+		
+	def _add_employee_leave_approver(self, employee, leave_approver):
+		webnotes.session.user = "Administrator"
+		employee = webnotes.bean("Employee", employee)
+		employee.doclist.append({
+			"doctype": "Employee Leave Approver",
+			"parentfield": "employee_leave_approvers",
+			"leave_approver": leave_approver
+		})
+		employee.save()
+	
 	def get_application(self, doclist):
 		application = webnotes.bean(copy=doclist)
 		application.doc.from_date = "2013-01-01"
@@ -11,8 +28,14 @@
 		return application
 
 	def test_block_list(self):
-		import webnotes
-		webnotes.conn.set_value("Department", "_Test Department", "leave_block_list", "_Test Leave Block List")
+		webnotes.session.user = "Administrator"
+		self._clear_roles()
+		
+		from webnotes.profile import add_role
+		add_role("test1@example.com", "HR User")
+			
+		webnotes.conn.set_value("Department", "_Test Department", 
+			"leave_block_list", "_Test Leave Block List")
 		
 		application = self.get_application(test_records[1])
 		application.insert()
@@ -20,9 +43,6 @@
 		self.assertRaises(LeaveDayBlockedError, application.submit)
 		
 		webnotes.session.user = "test1@example.com"
-		
-		from webnotes.profile import add_role
-		add_role("test1@example.com", "HR User")
 
 		# clear other applications
 		webnotes.conn.sql("delete from `tabLeave Application`")
@@ -31,11 +51,31 @@
 		self.assertTrue(application.insert())
 		
 	def test_overlap(self):
+		webnotes.session.user = "Administrator"
+		self._clear_roles()
+		self._clear_applications()
+		
+		from webnotes.profile import add_role
+		add_role("test@example.com", "Employee")
+		add_role("test2@example.com", "Leave Approver")
+		
+		webnotes.session.user = "test@example.com"
 		application = self.get_application(test_records[1])
+		application.doc.leave_approver = "test2@example.com"
+		application.insert()
+		
+		application = self.get_application(test_records[1])
+		application.doc.leave_approver = "test2@example.com"
 		self.assertRaises(OverlapError, application.insert)
 		
 	def test_global_block_list(self):
-		
+		webnotes.session.user = "Administrator"
+		self._clear_roles()
+
+		from webnotes.profile import add_role
+		add_role("test1@example.com", "Employee")
+		add_role("test@example.com", "Leave Approver")
+				
 		application = self.get_application(test_records[3])
 		application.doc.leave_approver = "test@example.com"
 		
@@ -44,19 +84,120 @@
 		webnotes.conn.set_value("Employee", "_T-Employee-0002", "department", 
 			"_Test Department")
 		
-		webnotes.session.user = "test2@example.com"
-		from webnotes.profile import add_role
-		add_role("test2@example.com", "Employee")
-
+		webnotes.session.user = "test1@example.com"
 		application.insert()
 		
 		webnotes.session.user = "test@example.com"
-		from webnotes.profile import add_role
-		add_role("test@example.com", "Leave Approver")
-		
 		application.doc.status = "Approved"
 		self.assertRaises(LeaveDayBlockedError, application.submit)
 		
+		webnotes.conn.set_value("Leave Block List", "_Test Leave Block List", 
+			"applies_to_all_departments", 0)
+		
+	def test_leave_approval(self):
+		webnotes.session.user = "Administrator"
+		self._clear_roles()
+		
+		from webnotes.profile import add_role
+		add_role("test@example.com", "Employee")
+		add_role("test1@example.com", "Leave Approver")
+		add_role("test2@example.com", "Leave Approver")
+		
+		self._test_leave_approval_basic_case_1()
+		self._test_leave_approval_basic_case_2()
+		self._test_leave_approval_invalid_leave_approver_insert()
+		self._test_leave_approval_invalid_leave_approver_submit()
+		self._test_leave_approval_valid_leave_approver_insert()
+		
+	def _test_leave_approval_basic_case_1(self):
+		self._clear_applications()
+		
+		# create leave application as Employee
+		webnotes.session.user = "test@example.com"
+		application = self.get_application(test_records[1])
+		application.doc.leave_approver = "test1@example.com"
+		application.insert()
+		
+		# submit leave application by Leave Approver
+		webnotes.session.user = "test1@example.com"
+		application.doc.status = "Approved"
+		application.submit()
+		self.assertEqual(webnotes.conn.get_value("Leave Application", application.doc.name,
+			"docstatus"), 1)
+		
+	def _test_leave_approval_basic_case_2(self):
+		self._clear_applications()
+		
+		# create leave application by any leave approver, 
+		# when no leave approver specified in employee's leave approvers list
+		application = self.get_application(test_records[1])
+		application.doc.leave_approver = "test1@example.com"
+		application.insert()
+		application.doc.status = "Approved"
+		application.submit()
+		self.assertEqual(webnotes.conn.get_value("Leave Application", application.doc.name,
+			"docstatus"), 1)
+		
+	def _test_leave_approval_invalid_leave_approver_insert(self):
+		from hr.doctype.leave_application.leave_application import InvalidLeaveApproverError
+		
+		self._clear_applications()
+		
+		# add a different leave approver in the employee's list
+		# should raise exception if not a valid leave approver
+		self._add_employee_leave_approver("_T-Employee-0001", "test2@example.com")
+		
+		# TODO - add test2@example.com leave approver in employee's leave approvers list
+		application = self.get_application(test_records[1])
+		webnotes.session.user = "test@example.com"
+		
+		application.doc.leave_approver = "test1@example.com"
+		self.assertRaises(InvalidLeaveApproverError, application.insert)
+		
+		webnotes.conn.sql("""delete from `tabEmployee Leave Approver` where parent=%s""",
+			"_T-Employee-0001")
+		
+	def _test_leave_approval_invalid_leave_approver_submit(self):
+		self._clear_applications()
+		self._add_employee_leave_approver("_T-Employee-0001", "test2@example.com")
+		
+		# create leave application as employee
+		# but submit as invalid leave approver - should raise exception
+		webnotes.session.user = "test@example.com"
+		application = self.get_application(test_records[1])
+		application.doc.leave_approver = "test2@example.com"
+		application.insert()
+		webnotes.session.user = "test1@example.com"
+		application.doc.status = "Approved"
+		
+		from webnotes.model.bean import BeanPermissionError
+		self.assertRaises(BeanPermissionError, application.submit)
+		
+		webnotes.conn.sql("""delete from `tabEmployee Leave Approver` where parent=%s""",
+			"_T-Employee-0001")
+		
+	def _test_leave_approval_valid_leave_approver_insert(self):
+		self._clear_applications()
+		self._add_employee_leave_approver("_T-Employee-0001", "test2@example.com")
+		
+		original_department = webnotes.conn.get_value("Employee", "_T-Employee-0001", "department")
+		webnotes.conn.set_value("Employee", "_T-Employee-0001", "department", None)
+		
+		# change to valid leave approver and try to create and submit leave application
+		webnotes.session.user = "test2@example.com"
+		application = self.get_application(test_records[1])
+		application.doc.leave_approver = "test2@example.com"
+		application.insert()
+		application.doc.status = "Approved"
+		application.submit()
+		self.assertEqual(webnotes.conn.get_value("Leave Application", application.doc.name,
+			"docstatus"), 1)
+			
+		webnotes.conn.sql("""delete from `tabEmployee Leave Approver` where parent=%s""",
+			"_T-Employee-0001")
+		
+		webnotes.conn.set_value("Employee", "_T-Employee-0001", "department", original_department)
+		
 test_dependencies = ["Leave Block List"]		
 
 test_records = [
diff --git a/hr/utils.py b/hr/utils.py
new file mode 100644
index 0000000..0d23a16
--- /dev/null
+++ b/hr/utils.py
@@ -0,0 +1,38 @@
+# 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
+from webnotes import _
+
+@webnotes.whitelist()
+def get_leave_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
+
+
+@webnotes.whitelist()
+def get_expense_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/patches/april_2013/p04_reverse_modules_list.py b/patches/april_2013/p04_reverse_modules_list.py
index 9215fea..1751d36 100644
--- a/patches/april_2013/p04_reverse_modules_list.py
+++ b/patches/april_2013/p04_reverse_modules_list.py
@@ -6,6 +6,7 @@
 	
 	ml = json.loads(webnotes.conn.get_global("modules_list") or "[]")
 	
-	webnotes.conn.set_global("hidden_modules", 
-		json.dumps(list(set(modules.keys()).difference(set(ml)))))
+	if ml:
+		webnotes.conn.set_global("hidden_modules", 
+			json.dumps(list(set(modules.keys()).difference(set(ml)))))
 	
\ No newline at end of file
diff --git a/patches/april_2013/p05_fixes_in_reverse_modules.py b/patches/april_2013/p05_fixes_in_reverse_modules.py
new file mode 100644
index 0000000..41e2e5e
--- /dev/null
+++ b/patches/april_2013/p05_fixes_in_reverse_modules.py
@@ -0,0 +1,10 @@
+import webnotes, json
+import webnotes.utils
+
+def execute():
+	modules = webnotes.get_config().modules
+	
+	ml = json.loads(webnotes.conn.get_global("hidden_modules") or "[]")
+	
+	if len(ml) == len(modules.keys()):
+		webnotes.conn.set_global("hidden_modules", json.dumps([]))
\ No newline at end of file
diff --git a/patches/december_2012/repost_ordered_qty.py b/patches/december_2012/repost_ordered_qty.py
index c798b6c..4b046f1 100644
--- a/patches/december_2012/repost_ordered_qty.py
+++ b/patches/december_2012/repost_ordered_qty.py
@@ -10,8 +10,6 @@
 			and po_item.item_code = %s and po_item.warehouse = %s
 		""", (d[0], d[1]))
 
-		if flt(d[3]) != flt(ordered_qty[0][0]):
-			print d[3], ordered_qty[0][0]
-			
+		if flt(d[3]) != flt(ordered_qty[0][0]):			
 			webnotes.conn.sql("""update `tabBin` set ordered_qty = %s where name = %s""",
 			 	(ordered_qty and ordered_qty[0][0] or 0, d[2]))
\ No newline at end of file
diff --git a/patches/february_2013/fix_outstanding.py b/patches/february_2013/fix_outstanding.py
index 22a6ee1..8afc63f 100644
--- a/patches/february_2013/fix_outstanding.py
+++ b/patches/february_2013/fix_outstanding.py
@@ -17,8 +17,4 @@
 			if ((r["against_voucher_type"]=='Sales Invoice' and flt(r["outstanding"]) >= 0) \
 				or (r["against_voucher_type"]=="Purchase Invoice" and flt(["outstanding"]) <= 0)):
 				webnotes.conn.set_value(r["against_voucher_type"], r["against_voucher"], 
-					"outstanding_amount", abs(flt(r["outstanding"])))
-			else:
-				print r["against_voucher_type"], r["against_voucher"], \
-					outstanding[0][1], abs(flt(r["outstanding"]))
-		
\ No newline at end of file
+					"outstanding_amount", abs(flt(r["outstanding"])))		
\ No newline at end of file
diff --git a/patches/january_2013/file_list_rename_returns.py b/patches/january_2013/file_list_rename_returns.py
index cca7a15..f897d5c 100644
--- a/patches/january_2013/file_list_rename_returns.py
+++ b/patches/january_2013/file_list_rename_returns.py
@@ -34,10 +34,8 @@
 				except Exception, e:
 					# if duplicate entry, then dont update
 					if e[0]!=1062:
-						print webnotes.getTraceback()
 						raise e
 		
-		print change_map
 		
 		changed_keys = change_map.keys()
 			
@@ -61,6 +59,5 @@
 				
 			except Exception, e:
 				if e[0]!=1146:
-					print webnotes.getTraceback()
 					raise e
 	
\ No newline at end of file
diff --git a/patches/july_2012/repost_stock_due_to_wrong_packing_list.py b/patches/july_2012/repost_stock_due_to_wrong_packing_list.py
index 81c6415..615d7ed 100644
--- a/patches/july_2012/repost_stock_due_to_wrong_packing_list.py
+++ b/patches/july_2012/repost_stock_due_to_wrong_packing_list.py
@@ -23,7 +23,6 @@
 	i = 0
 	for d in bins:
 		i += 1
-		print i
 		reserved_qty = webnotes.conn.sql("""
 			select 
 				sum((dnpi_qty / so_item_qty) * (so_item_qty - so_item_delivered_qty))
@@ -54,7 +53,6 @@
 		""", (d[0], d[1]))
 
 		if flt(d[3]) != flt(reserved_qty[0][0]):
-			print d[3], reserved_qty[0][0]
 			webnotes.conn.sql("""
 				update `tabBin` set reserved_qty = %s where name = %s
 			""", (reserved_qty and reserved_qty[0][0] or 0, d[2]))
@@ -77,7 +75,6 @@
 		)
 	""")
 	if sle:
-		print sle
 		for d in sle:
 			webnotes.conn.sql("update `tabStock Ledger Entry` set is_cancelled = 'Yes' where name = %s", d[3])
 			create_comment(d[3])
diff --git a/patches/mar_2012/doctype_get_refactor.py b/patches/mar_2012/doctype_get_refactor.py
index c6bfb31..2640229 100644
--- a/patches/mar_2012/doctype_get_refactor.py
+++ b/patches/mar_2012/doctype_get_refactor.py
@@ -24,7 +24,6 @@
 		* Create property setter entry of previous field
 		* Remove custom fields from tabDocField
 	"""
-	print "in handle custom fields"
 	cf = get_cf()
 	assign_idx(cf)
 	create_prev_field_prop_setter(cf)
@@ -120,7 +119,6 @@
 		webnotes.clear_cache(doctype=obj.doc.name)
 
 def change_to_decimal():
-	print "in change to decimal"
 	webnotes.conn.commit()
 	tables = webnotes.conn.sql("SHOW TABLES")
 	alter_tables_list = []
diff --git a/patches/march_2013/p03_update_buying_amount.py b/patches/march_2013/p03_update_buying_amount.py
index 0d96feb..92b171f 100644
--- a/patches/march_2013/p03_update_buying_amount.py
+++ b/patches/march_2013/p03_update_buying_amount.py
@@ -7,7 +7,6 @@
 
 	webnotes.conn.auto_commit_on_many_writes = True
 	for company in webnotes.conn.sql("select name from `tabCompany`"):
-		print company[0]
 		stock_ledger_entries = webnotes.conn.sql("""select item_code, voucher_type, voucher_no,
 			voucher_detail_no, posting_date, posting_time, stock_value, 
 			warehouse, actual_qty as qty from `tabStock Ledger Entry` 
@@ -17,7 +16,6 @@
 		
 		dn_list = webnotes.conn.sql("""select name from `tabDelivery Note` 
 			where docstatus < 2 and company = %s""", company[0])
-		print "Total Delivery Note: ", len(dn_list)
 		
 		for dn in dn_list:
 			dn = webnotes.get_obj("Delivery Note", dn[0], with_children = 1)
@@ -25,7 +23,6 @@
 		
 		si_list = webnotes.conn.sql("""select name from `tabSales Invoice` 
 			where docstatus < 2	and company = %s""", company[0])
-		print "Total Sales Invoice: ", len(si_list)
 		for si in si_list:
 			si = webnotes.get_obj("Sales Invoice", si[0], with_children = 1)
 			si.set_buying_amount(stock_ledger_entries)
diff --git a/patches/march_2013/p08_create_aii_accounts.py b/patches/march_2013/p08_create_aii_accounts.py
index 30bfe9e..00230d8 100644
--- a/patches/march_2013/p08_create_aii_accounts.py
+++ b/patches/march_2013/p08_create_aii_accounts.py
@@ -56,12 +56,13 @@
 			where company=%s and ifnull(parent_account, '')=''""", company)[0][0]
 		
 		if count > 4:
-			print "Company", company, \
-				"has more than 4 root accounts. cannot apply patch to this company."
+			webnotes.errprint("Company" + company + 
+				"has more than 4 root accounts. cannot apply patch to this company.")
 			continue
 		
 		for account_name, parent_account_name, group_or_ledger, account_type in accounts_to_add:
-			if not webnotes.conn.exists("Account", "%s - %s" % (account_name, abbr)):
+			if not webnotes.conn.sql("""select name from `tabAccount` where account_name = %s 
+					and company = %s""", (account_name, company)):
 				parent_account = "%s - %s" % (parent_account_name, abbr)
 				if check_fn:
 					parent_account = check_fn(parent_account, company)
@@ -77,12 +78,13 @@
 				
 def add_aii_cost_center():
 	for company, abbr in webnotes.conn.sql("""select name, abbr from `tabCompany`"""):
-		if not webnotes.conn.exists("Cost Center", "Auto Inventory Accounting - %s" % abbr):
+		if not webnotes.conn.sql("""select name from `tabCost Center` where cost_center_name = 
+				'Auto Inventory Accounting' and company_name = %s""", company):
 			parent_cost_center = webnotes.conn.get_value("Cost Center", 
 				{"parent_cost_center['']": '', "company_name": company})
 				
 			if not parent_cost_center:
-				print "Company", company, "does not have a root cost center"
+				webnotes.errprint("Company " + company + "does not have a root cost center")
 				continue
 			
 			cc = webnotes.bean({
diff --git a/patches/may_2012/reload_sales_invoice_pf.py b/patches/may_2012/reload_sales_invoice_pf.py
index b784469..ea4f5df 100644
--- a/patches/may_2012/reload_sales_invoice_pf.py
+++ b/patches/may_2012/reload_sales_invoice_pf.py
@@ -12,6 +12,5 @@
 					'Sales Invoice Spartan',
 					'Sales Invoice Modern'
 				]:
-			print r.get('name')
 			webnotes.modules.reload_doc(r.get('module'), 'Print Format', r.get('name'))		
 			
\ No newline at end of file
diff --git a/patches/october_2012/fix_cancelled_gl_entries.py b/patches/october_2012/fix_cancelled_gl_entries.py
index 9d23619..5c23ce8 100644
--- a/patches/october_2012/fix_cancelled_gl_entries.py
+++ b/patches/october_2012/fix_cancelled_gl_entries.py
@@ -12,5 +12,4 @@
 					where voucher_type = %s and voucher_no = %s""", 
 					(entry['voucher_type'], entry['voucher_no']))
 		except Exception, e:
-			print entry
-			print e			
+			pass
\ No newline at end of file
diff --git a/patches/patch_list.py b/patches/patch_list.py
index b827c5b..79e6f59 100644
--- a/patches/patch_list.py
+++ b/patches/patch_list.py
@@ -231,7 +231,6 @@
 	"patches.march_2013.p12_set_item_tax_rate_in_json",
 	"patches.march_2013.p07_update_valuation_rate",
 	"patches.march_2013.p08_create_aii_accounts",
-	"patches.march_2013.p03_update_buying_amount",
 	"patches.april_2013.p01_update_serial_no_valuation_rate",
 	"patches.april_2013.p02_add_country_and_currency",
 	"patches.april_2013.p03_fixes_for_lead_in_quotation",
@@ -241,4 +240,6 @@
 	"patches.april_2013.p04_reverse_modules_list",
 	"execute:webnotes.delete_doc('Search Criteria', 'time_log_summary')",
 	"patches.april_2013.p04_update_role_in_pages",
+	"patches.april_2013.p05_fixes_in_reverse_modules",
+	"execute:webnotes.delete_doc('DocType Mapper', 'Delivery Note-Packing Slip')"
 ]
\ No newline at end of file
diff --git a/public/js/queries.js b/public/js/queries.js
index e15e686..9809cd9 100644
--- a/public/js/queries.js
+++ b/public/js/queries.js
@@ -133,10 +133,8 @@
 		WHERE tabItem.docstatus!=2 \
 		AND (ifnull(`tabItem`.`end_of_life`,"") in ("", "0000-00-00") \
 			OR `tabItem`.`end_of_life` > NOW()) \
-		AND tabItem.%(key)s LIKE "%s" ' + (conditions 
-			? (" AND " + conditions.join(" AND "))
-			: "")
-		+ " LIMIT 50"
+		AND (tabItem.%(key)s LIKE \"%s\" OR tabItem.item_name LIKE \"%%%s\")' + 
+			(conditions ? (" AND " + conditions.join(" AND ")) : "") + " LIMIT 50"
 }
 
 erpnext.queries.item_std = function() {
diff --git a/public/js/startup.js b/public/js/startup.js
index 0a6580b..76f2c26 100644
--- a/public/js/startup.js
+++ b/public/js/startup.js
@@ -136,10 +136,7 @@
 
 erpnext.hide_naming_series = function() {
 	if(cur_frm.fields_dict.naming_series) {
-		hide_field('naming_series');
-		if(cur_frm.doc.__islocal) {
-			unhide_field('naming_series');
-		}
+		cur_frm.toggle_display("naming_series", cur_frm.doc.__islocal?true:false);
 	}
 }
 
diff --git a/selling/doctype/lead/lead.txt b/selling/doctype/lead/lead.txt
index e162551..2463f01 100644
--- a/selling/doctype/lead/lead.txt
+++ b/selling/doctype/lead/lead.txt
@@ -1,8 +1,8 @@
 [
  {
-  "creation": "2013-01-28 17:07:01", 
+  "creation": "2013-04-10 11:45:37", 
   "docstatus": 0, 
-  "modified": "2013-03-26 14:05:01", 
+  "modified": "2013-04-10 11:49:11", 
   "modified_by": "Administrator", 
   "owner": "Administrator"
  }, 
@@ -23,13 +23,18 @@
   "permlevel": 0
  }, 
  {
+  "amend": 0, 
+  "create": 1, 
   "doctype": "DocPerm", 
   "name": "__common__", 
   "parent": "Lead", 
   "parentfield": "permissions", 
   "parenttype": "DocType", 
+  "permlevel": 0, 
   "read": 1, 
-  "submit": 0
+  "report": 1, 
+  "submit": 0, 
+  "write": 1
  }, 
  {
   "doctype": "DocType", 
@@ -445,69 +450,13 @@
   "label": "Blog Subscriber"
  }, 
  {
-  "create": 1, 
-  "doctype": "DocPerm", 
-  "permlevel": 0, 
-  "report": 1, 
-  "role": "Guest", 
-  "write": 1
- }, 
- {
-  "amend": 0, 
-  "cancel": 0, 
-  "create": 0, 
-  "doctype": "DocPerm", 
-  "permlevel": 1, 
-  "report": 0, 
-  "role": "Sales User", 
-  "write": 0
- }, 
- {
-  "amend": 0, 
-  "cancel": 0, 
-  "create": 0, 
-  "doctype": "DocPerm", 
-  "permlevel": 1, 
-  "report": 0, 
-  "role": "Sales Manager", 
-  "write": 0
- }, 
- {
-  "amend": 0, 
   "cancel": 1, 
-  "create": 1, 
   "doctype": "DocPerm", 
-  "permlevel": 0, 
-  "report": 1, 
-  "role": "Sales Manager", 
-  "write": 1
+  "role": "Sales Manager"
  }, 
  {
-  "amend": 0, 
   "cancel": 0, 
-  "create": 1, 
   "doctype": "DocPerm", 
-  "permlevel": 0, 
-  "report": 1, 
-  "role": "Sales User", 
-  "write": 1
- }, 
- {
-  "amend": 0, 
-  "cancel": 0, 
-  "create": 0, 
-  "doctype": "DocPerm", 
-  "permlevel": 1, 
-  "role": "All"
- }, 
- {
-  "amend": 0, 
-  "cancel": 0, 
-  "create": 1, 
-  "doctype": "DocPerm", 
-  "permlevel": 0, 
-  "report": 1, 
-  "role": "System Manager", 
-  "write": 1
+  "role": "Sales User"
  }
 ]
\ No newline at end of file
diff --git a/selling/doctype/sales_common/sales_common.py b/selling/doctype/sales_common/sales_common.py
index b9f9af6..7b1528b 100644
--- a/selling/doctype/sales_common/sales_common.py
+++ b/selling/doctype/sales_common/sales_common.py
@@ -125,8 +125,7 @@
 	def get_item_details(self, args, obj):
 		import json
 		if not obj.doc.price_list_name:
-			msgprint("Please Select Price List before selecting Items")
-			raise Exception
+			msgprint("Please Select Price List before selecting Items", raise_exception=True)
 		item = webnotes.conn.sql("""select description, item_name, brand, item_group, stock_uom, 
 			default_warehouse, default_income_account, default_sales_cost_center, 
 			purchase_account, description_html, barcode from `tabItem` 
diff --git a/selling/search_criteria/sales_personwise_transaction_summary/sales_personwise_transaction_summary.js b/selling/search_criteria/sales_personwise_transaction_summary/sales_personwise_transaction_summary.js
index 335df7a..79dd9d5 100755
--- a/selling/search_criteria/sales_personwise_transaction_summary/sales_personwise_transaction_summary.js
+++ b/selling/search_criteria/sales_personwise_transaction_summary/sales_personwise_transaction_summary.js
@@ -39,10 +39,7 @@
   sp = this.get_filter('Sales Person', 'Sales Person').get_value();
 
   date_fld = 'transaction_date';
-  if(based_on == 'Sales Invoice') {
-    based_on = 'Sales Invoice';
-    date_fld = 'posting_date';
-  }
+  if(based_on == 'Sales Invoice' || based_on == "Delivery Note") date_fld = 'posting_date';
 
   sp_cond = '';
   if (from_date) sp_cond += ' AND t1.' + date_fld + '>= "' + from_date + '"';
diff --git a/setup/doctype/company/company.py b/setup/doctype/company/company.py
index bee1333..964b886 100644
--- a/setup/doctype/company/company.py
+++ b/setup/doctype/company/company.py
@@ -153,7 +153,7 @@
 		for d in acc_list_common:
 			self.add_acc(d)
 
-		country = sql("select value from tabSingles where field = 'country' and doctype = 'Control Panel'")
+		country = webnotes.conn.sql("select value from tabSingles where field = 'country' and doctype = 'Control Panel'")
 		country = country and cstr(country[0][0]) or ''
 
 		# load taxes (only for India)
@@ -265,26 +265,31 @@
 		"""
 			Trash accounts and cost centers for this company if no gl entry exists
 		"""
-		rec = sql("SELECT name from `tabGL Entry` where ifnull(is_cancelled, 'No') = 'No' and company = %s", self.doc.name)
+		rec = webnotes.conn.sql("SELECT name from `tabGL Entry` where ifnull(is_cancelled, 'No') = 'No' and company = %s", self.doc.name)
 		if not rec:
 			# delete gl entry
-			sql("delete from `tabGL Entry` where company = %s", self.doc.name)
+			webnotes.conn.sql("delete from `tabGL Entry` where company = %s", self.doc.name)
 
 			#delete tabAccount
-			sql("delete from `tabAccount` where company = %s order by lft desc, rgt desc", self.doc.name)
+			webnotes.conn.sql("delete from `tabAccount` where company = %s order by lft desc, rgt desc", self.doc.name)
 			
 			#delete cost center child table - budget detail
-			sql("delete bd.* from `tabBudget Detail` bd, `tabCost Center` cc where bd.parent = cc.name and cc.company_name = %s", self.doc.name)
+			webnotes.conn.sql("delete bd.* from `tabBudget Detail` bd, `tabCost Center` cc where bd.parent = cc.name and cc.company_name = %s", self.doc.name)
 			#delete cost center
-			sql("delete from `tabCost Center` WHERE company_name = %s order by lft desc, rgt desc", self.doc.name)
+			webnotes.conn.sql("delete from `tabCost Center` WHERE company_name = %s order by lft desc, rgt desc", self.doc.name)
 			
-			webnotes.defaults.clear_default("company", value=self.doc.name)
+		webnotes.defaults.clear_default("company", value=self.doc.name)
 			
-			#update value as blank for tabSingles Global Defaults
-			sql("update `tabSingles` set value = '' where doctype='Global Defaults' and field = 'default_company' and value = %s", self.doc.name)
-
+		webnotes.conn.sql("""update `tabSingles` set value=""
+			where doctype='Global Defaults' and field='default_company' 
+			and value=%s""", self.doc.name)
+			
 	def on_rename(self,newdn,olddn):
-		sql("update `tabCompany` set company_name = '%s' where name = '%s'" %(newdn,olddn))	
-		sql("update `tabSingles` set value = %s where doctype='Global Defaults' and field = 'default_company' and value = %s", (newdn, olddn))	
-		if webnotes.defaults.get_global_default('company') == olddn:
-			webnotes.defaults.set_global_default('company', newdn)
\ No newline at end of file
+		webnotes.conn.sql("""update `tabCompany` set company_name=%s
+			where name=%s""", (newdn, olddn))
+		
+		webnotes.conn.sql("""update `tabSingles` set value=%s
+			where doctype='Global Defaults' and field='default_company' 
+			and value=%s""", (newdn, olddn))
+		
+		webnotes.defaults.clear_default("company", value=olddn)
\ No newline at end of file
diff --git a/setup/doctype/email_digest/email_digest.py b/setup/doctype/email_digest/email_digest.py
index 0b0b21a..881e35a 100644
--- a/setup/doctype/email_digest/email_digest.py
+++ b/setup/doctype/email_digest/email_digest.py
@@ -94,8 +94,7 @@
 				msg_for_this_receipient = self.get_msg_html(self.get_user_specific_content(user_id) + \
 					common_msg)
 				from webnotes.utils.email_lib import sendmail
-				sendmail(recipients=user_id, subject=(self.doc.frequency + " Digest"),
-					sender="ERPNext Notifications <notifications+email_digest@erpnext.com>",
+				sendmail(recipients=user_id, subject="[ERPNext] " + (self.doc.frequency + " Digest"),
 					msg=msg_for_this_receipient)
 			
 	def get_digest_msg(self):
diff --git a/stock/DocType Mapper/Delivery Note-Packing Slip/Delivery Note-Packing Slip.txt b/stock/DocType Mapper/Delivery Note-Packing Slip/Delivery Note-Packing Slip.txt
index 79b17c2..fc88bba 100644
--- a/stock/DocType Mapper/Delivery Note-Packing Slip/Delivery Note-Packing Slip.txt
+++ b/stock/DocType Mapper/Delivery Note-Packing Slip/Delivery Note-Packing Slip.txt
@@ -2,7 +2,7 @@
  {
   "creation": "2012-02-02 11:50:33", 
   "docstatus": 0, 
-  "modified": "2013-04-05 16:08:22", 
+  "modified": "2013-04-16 12:26:28", 
   "modified_by": "Administrator", 
   "owner": "Administrator"
  }, 
@@ -61,6 +61,13 @@
   "to_field": "dn_detail"
  }, 
  {
+  "doctype": "Field Mapper Detail", 
+  "from_field": "eval: flt(obj.qty) - flt(obj.packed_qty)", 
+  "map": "Yes", 
+  "match_id": 1, 
+  "to_field": "qty"
+ }, 
+ {
   "doctype": "Table Mapper Detail", 
   "from_table": "Delivery Note", 
   "match_id": 0, 
diff --git a/stock/doctype/delivery_note/delivery_note.js b/stock/doctype/delivery_note/delivery_note.js
index f47040d..8d09cbd 100644
--- a/stock/doctype/delivery_note/delivery_note.js
+++ b/stock/doctype/delivery_note/delivery_note.js
@@ -158,7 +158,6 @@
 }
 
 
-// ****************************** DELIVERY TYPE ************************************
 cur_frm.cscript.delivery_type = function(doc, cdt, cdn) {
 	if (doc.delivery_type = 'Sample') cfn_set_fields(doc, cdt, cdn);
 }
@@ -185,7 +184,6 @@
 	return 'SELECT DISTINCT `tabSupplier`.`name` FROM `tabSupplier` WHERE `tabSupplier`.supplier_type = "transporter" AND `tabSupplier`.docstatus != 2 AND `tabSupplier`.%(key)s LIKE "%s" ORDER BY `tabSupplier`.`name` LIMIT 50';
 }
 
-//-----------------------------------Make Sales Invoice----------------------------------------------
 cur_frm.cscript['Make Sales Invoice'] = function() {
 	var doc = cur_frm.doc
 	n = wn.model.make_new_doc_and_get_name('Sales Invoice');
@@ -201,7 +199,6 @@
 	);
 }
 
-//-----------------------------------Make Installation Note----------------------------------------------
 cur_frm.cscript['Make Installation Note'] = function() {
 	var doc = cur_frm.doc;
 	if(doc.per_installed < 99.99){
@@ -221,31 +218,19 @@
 		msgprint("Item installation is already completed")
 }
 
-//-----------------------------------Make Sales Invoice----------------------------------------------
 cur_frm.cscript['Make Packing Slip'] = function() {
-	var doc = cur_frm.doc
 	n = wn.model.make_new_doc_and_get_name('Packing Slip');
-	$c('dt_map', args={
-		'docs':wn.model.compress([locals['Packing Slip'][n]]),
-		'from_doctype':doc.doctype,
-		'to_doctype':'Packing Slip',
-		'from_docname':doc.name,
-		'from_to_list':"[['Delivery Note','Packing Slip'],['Delivery Note Item','Packing Slip Item']]"
-		}, function(r,rt) {
-			 loaddoc('Packing Slip', n);
-		}
-	);
+	ps = locals["Packing Slip"][n];
+	ps.delivery_note = cur_frm.doc.name;
+	loaddoc('Packing Slip', n);
 }
 
 
 //get query select Territory
-//=======================================================================================================================
 cur_frm.fields_dict['territory'].get_query = function(doc,cdt,cdn) {
 	return 'SELECT `tabTerritory`.`name`,`tabTerritory`.`parent_territory` FROM `tabTerritory` WHERE `tabTerritory`.`is_group` = "No" AND `tabTerritory`.`docstatus`!= 2 AND `tabTerritory`.%(key)s LIKE "%s"	ORDER BY	`tabTerritory`.`name` ASC LIMIT 50';
 }
 
-//------------------------for printing without amount----------
-
 var set_print_hide= function(doc, cdt, cdn){
 	var dn_fields = wn.meta.docfield_map['Delivery Note'];
 	var dn_item_fields = wn.meta.docfield_map['Delivery Note Item'];
diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py
index 0019698..15e24ef 100644
--- a/stock/doctype/delivery_note/delivery_note.py
+++ b/stock/doctype/delivery_note/delivery_note.py
@@ -20,7 +20,7 @@
 from webnotes.utils import cstr, flt, getdate, cint
 from webnotes.model.bean import getlist
 from webnotes.model.code import get_obj
-from webnotes import msgprint
+from webnotes import msgprint, _
 import webnotes.defaults
 
 
@@ -333,17 +333,15 @@
 		"""
 			Cancel submitted packing slips related to this delivery note
 		"""
-		res = webnotes.conn.sql("""\
-			SELECT name, count(*) FROM `tabPacking Slip`
-			WHERE delivery_note = %s AND docstatus = 1
-			""", self.doc.name)
+		res = webnotes.conn.sql("""SELECT name FROM `tabPacking Slip` WHERE delivery_note = %s 
+			AND docstatus = 1""", self.doc.name)
 
-		if res and res[0][1]>0:
+		if res:
 			from webnotes.model.bean import Bean
 			for r in res:
 				ps = Bean(dt='Packing Slip', dn=r[0])
 				ps.cancel()
-			webnotes.msgprint("%s Packing Slip(s) Cancelled" % res[0][1])
+			webnotes.msgprint(_("Packing Slip(s) Cancelled"))
 
 
 	def update_stock_ledger(self, update_stock):
@@ -421,4 +419,4 @@
 				
 		if gl_entries:
 			from accounts.general_ledger import make_gl_entries
-			make_gl_entries(gl_entries)
+			make_gl_entries(gl_entries)
\ No newline at end of file
diff --git a/stock/doctype/delivery_note_item/delivery_note_item.txt b/stock/doctype/delivery_note_item/delivery_note_item.txt
index fb3dd41..f3b2417 100644
--- a/stock/doctype/delivery_note_item/delivery_note_item.txt
+++ b/stock/doctype/delivery_note_item/delivery_note_item.txt
@@ -2,7 +2,7 @@
  {
   "creation": "2013-03-26 11:03:09", 
   "docstatus": 0, 
-  "modified": "2013-03-28 15:42:41", 
+  "modified": "2013-04-17 17:20:45", 
   "modified_by": "Administrator", 
   "owner": "Administrator"
  }, 
@@ -333,17 +333,6 @@
   "width": "150px"
  }, 
  {
-  "allow_on_submit": 1, 
-  "default": "0", 
-  "doctype": "DocField", 
-  "fieldname": "packed_qty", 
-  "fieldtype": "Float", 
-  "label": "Packed Quantity", 
-  "no_copy": 1, 
-  "print_hide": 1, 
-  "read_only": 1
- }, 
- {
   "doctype": "DocField", 
   "fieldname": "prevdoc_doctype", 
   "fieldtype": "Data", 
diff --git a/stock/doctype/item/item.py b/stock/doctype/item/item.py
index 55a0ae7..a16296d 100644
--- a/stock/doctype/item/item.py
+++ b/stock/doctype/item/item.py
@@ -22,12 +22,10 @@
 from webnotes.model.bean import getlist
 from webnotes import msgprint, _
 
-sql = webnotes.conn.sql
-
 from webnotes.model.controller import DocListController
 class DocType(DocListController):
 	def get_tax_rate(self, tax_type):
-		rate = sql("select tax_rate from tabAccount where name = %s", tax_type)
+		rate = webnotes.conn.sql("select tax_rate from tabAccount where name = %s", tax_type)
 		ret = {
 			'tax_rate'	:	rate and flt(rate[0][0]) or 0
 		}
@@ -39,7 +37,8 @@
 		# webpage updates
 		self.update_website()
 			
-		bin = sql("select stock_uom from `tabBin` where item_code = '%s' " % self.doc.item_code)
+		bin = webnotes.conn.sql("select stock_uom from `tabBin` where item_code = %s", 
+			self.doc.item_code)
 		if bin and cstr(bin[0][0]) and cstr(bin[0][0]) != cstr(self.doc.stock_uom):
 			msgprint("Please Update Stock UOM with the help of Stock UOM Replace Utility.")
 			raise Exception
@@ -107,8 +106,8 @@
 
 	# On delete 1. Delete BIN (if none of the corrosponding transactions present, it gets deleted. if present, rolled back due to exception)
 	def on_trash(self):
-		sql("""delete from tabBin where item_code=%s""", self.doc.item_code)
-		sql("""delete from `tabStock Ledger Entry` 
+		webnotes.conn.sql("""delete from tabBin where item_code=%s""", self.doc.item_code)
+		webnotes.conn.sql("""delete from `tabStock Ledger Entry` 
 			where item_code=%s and is_cancelled='Yes' """, self.doc.item_code)
 		
 		if self.doc.page_name:
@@ -149,7 +148,7 @@
 
 	def check_for_active_boms(self, field_label):
 		if field_label in ['Is Active', 'Is Purchase Item']:
-			bom_mat = sql("select distinct t1.parent from `tabBOM Item` t1, `tabBOM` t2 where t1.item_code ='%s' and (t1.bom_no = '' or t1.bom_no is NULL) and t2.name = t1.parent and t2.is_active = 1 and t2.docstatus = 1 and t1.docstatus =1 " % self.doc.name )
+			bom_mat = webnotes.conn.sql("select distinct t1.parent from `tabBOM Item` t1, `tabBOM` t2 where t1.item_code =%s and (t1.bom_no = '' or t1.bom_no is NULL) and t2.name = t1.parent and t2.is_active = 1 and t2.docstatus = 1 and t1.docstatus =1 ", self.doc.name)
 			if bom_mat and bom_mat[0][0]:
 				msgprint("%s should be 'Yes'. As Item %s is present in one or many Active BOMs." % (cstr(field_label), cstr(self.doc.name)))
 				raise Exception
@@ -157,25 +156,27 @@
 				and self.doc.is_sub_contracted_item != 'Yes') 
 				or (field_label == 'Is Sub Contracted Item' 
 				and self.doc.is_manufactured_item != 'Yes')):
-			bom = sql("select name from `tabBOM` where item = '%s' and is_active = 1" % cstr(self.doc.name))
+			bom = webnotes.conn.sql("select name from `tabBOM` where item = %s and is_active = 1",
+				(self.doc.name,))
 			if bom and bom[0][0]:
 				msgprint("%s should be 'Yes'. As Item %s is present in one or many Active BOMs." % (cstr(field_label), cstr(self.doc.name)))
 				raise Exception
 				
 	def validate_barcode(self):
 		if self.doc.barcode:
-			duplicate = sql("select name from tabItem where barcode = %s and name != %s", (self.doc.barcode, self.doc.name))
+			duplicate = webnotes.conn.sql("select name from tabItem where barcode = %s and name != %s", (self.doc.barcode, self.doc.name))
 			if duplicate:
 				msgprint("Barcode: %s already used in item: %s" % (self.doc.barcode, cstr(duplicate[0][0])), raise_exception = 1)
 
 	def validate(self):
-		fl = {'is_manufactured_item'	:'Allow Bill of Materials',
+		if not cint(self.doc.fields.get("__islocal")):
+			fl = {'is_manufactured_item'	:'Allow Bill of Materials',
 					'is_sub_contracted_item':'Is Sub Contracted Item',
 					'is_purchase_item'			:'Is Purchase Item',
 					'is_pro_applicable'		 :'Allow Production Order'}
-		for d in fl:
-			if cstr(self.doc.fields.get(d)) != 'Yes':
-				self.check_for_active_boms(fl[d])
+			for d in fl:
+				if cstr(self.doc.fields.get(d)) != 'Yes':
+					self.check_for_active_boms(fl[d])
 		self.check_ref_rate_detail()
 		self.fill_customer_code()
 		self.check_item_tax()
@@ -197,7 +198,7 @@
 								
 	def check_non_asset_warehouse(self):
 		if self.doc.is_asset_item == "Yes":
-			existing_qty = sql("select t1.warehouse, t1.actual_qty from tabBin t1, tabWarehouse t2 where t1.item_code=%s and (t2.warehouse_type!='Fixed Asset' or t2.warehouse_type is null) and t1.warehouse=t2.name and t1.actual_qty > 0", self.doc.name)
+			existing_qty = webnotes.conn.sql("select t1.warehouse, t1.actual_qty from tabBin t1, tabWarehouse t2 where t1.item_code=%s and (t2.warehouse_type!='Fixed Asset' or t2.warehouse_type is null) and t1.warehouse=t2.name and t1.actual_qty > 0", self.doc.name)
 			for e in existing_qty:
 				msgprint("%s Units exist in Warehouse %s, which is not an Asset Warehouse." % (e[1],e[0]))
 			if existing_qty:
@@ -206,7 +207,7 @@
 				raise Exception
 
 	def get_file_details(self, arg = ''):
-		file = sql("select file_group, description from tabFile where name = %s", eval(arg)['file_name'], as_dict = 1)
+		file = webnotes.conn.sql("select file_group, description from tabFile where name = %s", eval(arg)['file_name'], as_dict = 1)
 
 		ret = {
 			'file_group'	:	file and file[0]['file_group'] or '',
@@ -216,11 +217,11 @@
 		
 
 	def check_if_sle_exists(self):
-		sle = sql("select name from `tabStock Ledger Entry` where item_code = %s and ifnull(is_cancelled, 'No') = 'No'", self.doc.name)
+		sle = webnotes.conn.sql("select name from `tabStock Ledger Entry` where item_code = %s and ifnull(is_cancelled, 'No') = 'No'", self.doc.name)
 		return sle and 'exists' or 'not exists'
 
 	def on_rename(self,newdn,olddn):
-		sql("update tabItem set item_code = %s where name = %s", (newdn, olddn))
+		webnotes.conn.sql("update tabItem set item_code = %s where name = %s", (newdn, olddn))
 		if self.doc.page_name:
 			from webnotes.webutils import clear_cache
 			clear_cache(self.doc.page_name)
@@ -239,10 +240,10 @@
 			vals = webnotes.conn.get_value("Item", self.doc.name, 
 				["has_serial_no", "is_stock_item", "valuation_method"], as_dict=True)
 			
-			if vals and (vals.has_serial_no != self.doc.has_serial_no or 
-				vals.is_stock_item != self.doc.is_stock_item or 
+			if vals and ((self.doc.is_stock_item == "No" and vals.is_stock_item == "Yes") or 
+				vals.has_serial_no != self.doc.has_serial_no or 
 				vals.valuation_method != self.doc.valuation_method):
-					if self.check_if_sle_exists():
+					if self.check_if_sle_exists() == "exists":
 						webnotes.msgprint(_("As there are existing stock transactions for this \
 							item, you can not change the values of 'Has Serial No', \
 							'Is Stock Item' and 'Valuation Method'"), raise_exception=1)
diff --git a/stock/doctype/packing_slip/packing_slip.js b/stock/doctype/packing_slip/packing_slip.js
index 4c20289..18a2486 100644
--- a/stock/doctype/packing_slip/packing_slip.js
+++ b/stock/doctype/packing_slip/packing_slip.js
@@ -23,52 +23,36 @@
 		function(doc, cdt, cdn) {
 	var query = 'SELECT name, item_name, description FROM `tabItem` WHERE name IN ( \
 		SELECT item_code FROM `tabDelivery Note Item` dnd \
-		WHERE parent="'	+ doc.delivery_note + '" AND IFNULL(qty, 0) > IFNULL(packed_qty, 0)) AND %(key)s LIKE "%s" LIMIT 50';
+		WHERE parent="'	+ doc.delivery_note + '" AND IFNULL(qty, 0) > IFNULL(packed_qty, 0)) \
+		AND %(key)s LIKE "%s" LIMIT 50';
 	return query;
 }
 
-
-// Fetch item details
-cur_frm.add_fetch("item_code", "item_name", "item_name");
-cur_frm.add_fetch("item_code", "stock_uom", "stock_uom");
-cur_frm.add_fetch("item_code", "net_weight", "net_weight");
-cur_frm.add_fetch("item_code", "weight_uom", "weight_uom");
-
 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.net_weight) && cstr(ps_detail.weight_uom))) {
-			cur_frm.cscript.update_item_details(doc);
-		}
+			cur_frm.cscript.get_items(doc, cdt, cdn);
 	}
 }
 
-cur_frm.cscript.refresh = function(doc, dt, dn) {
-	if(!doc.amended_from) {
-		hide_field('misc_details');
-	} else {
-		unhide_field('misc_details');
-	}
-}
-
-
-cur_frm.cscript.update_item_details = function(doc) {
-	$c_obj(make_doclist(doc.doctype, doc.name), 'update_item_details', '', function(r, rt) {
-		if(r.exc) {
-			msgprint(r.exc);
-		} else {
-			refresh_many(['item_details', 'naming_series', 'from_case_no', 'to_case_no'])
+cur_frm.cscript.get_items = function(doc, cdt, cdn) {
+	this.frm.call({
+		doc: this.frm.doc,
+		method: "get_items",
+		callback: function(r) {
+			if(!r.exc) cur_frm.refresh();
 		}
 	});
 }
 
+cur_frm.cscript.refresh = function(doc, dt, dn) {
+	cur_frm.toggle_display("misc_details", doc.amended_from);
+}
 
 cur_frm.cscript.validate = function(doc, cdt, cdn) {
 	cur_frm.cscript.validate_case_nos(doc);
 	cur_frm.cscript.validate_calculate_item_details(doc);
 }
 
-
 // To Case No. cannot be less than From Case No.
 cur_frm.cscript.validate_case_nos = function(doc) {
 	doc = locals[doc.doctype][doc.name];
@@ -99,7 +83,7 @@
 cur_frm.cscript.validate_duplicate_items = function(doc, ps_detail) {
 	for(var i=0; i<ps_detail.length; i++) {
 		for(var j=0; j<ps_detail.length; j++) {
-			if(i!=j && ps_detail[i].dn_detail && ps_detail[i].dn_detail==ps_detail[j].dn_detail) {
+			if(i!=j && ps_detail[i].item_code && ps_detail[i].item_code==ps_detail[j].item_code) {
 				msgprint("You have entered duplicate items. Please rectify and try again.");
 				validated = false;
 				return;
@@ -138,3 +122,17 @@
 	refresh_many(['net_weight_pkg', 'net_weight_uom', 'gross_weight_uom', 'gross_weight_pkg']);
 }
 
+var make_row = function(title,val,bold){
+	var bstart = '<b>'; var bend = '</b>';
+	return '<tr><td class="datalabelcell">'+(bold?bstart:'')+title+(bold?bend:'')+'</td>'
+	 +'<td class="datainputcell" style="text-align:left;">'+ val +'</td>'
+	 +'</tr>'
+}
+
+cur_frm.pformat.net_weight_pkg= function(doc){
+	return '<table style="width:100%">' + make_row('Net Weight', doc.net_weight_pkg) + '</table>'
+}
+
+cur_frm.pformat.gross_weight_pkg= function(doc){
+	return '<table style="width:100%">' + make_row('Gross Weight', doc.gross_weight_pkg) + '</table>'
+}
\ No newline at end of file
diff --git a/stock/doctype/packing_slip/packing_slip.py b/stock/doctype/packing_slip/packing_slip.py
index fb2fd53..1375108 100644
--- a/stock/doctype/packing_slip/packing_slip.py
+++ b/stock/doctype/packing_slip/packing_slip.py
@@ -16,13 +16,14 @@
 
 from __future__ import unicode_literals
 import webnotes
-from webnotes.utils import flt, cint, now
+from webnotes.utils import flt, cint
+from webnotes import msgprint, _
+from webnotes.model.doc import addchild
 
 class DocType:
 	def __init__(self, d, dl):
 		self.doc, self.doclist = d, dl
 
-
 	def validate(self):
 		"""
 			* Validate existence of submitted Delivery Note
@@ -32,48 +33,48 @@
 			It is necessary to validate case nos before checking quantity
 		"""
 		self.validate_delivery_note()
+		self.validate_items_mandatory()
 		self.validate_case_nos()
 		self.validate_qty()
 
-
 	def validate_delivery_note(self):
 		"""
-			Validates if delivery note has status as submitted
+			Validates if delivery note has status as draft
 		"""
-		res = webnotes.conn.sql("""SELECT docstatus FROM `tabDelivery Note` 
-			WHERE name=%(delivery_note)s""", self.doc.fields)
-
-		if not(res and res[0][0]==0):
-			webnotes.msgprint("""Invalid Delivery Note. Delivery Note should exist 
-				and should be in draft state. Please rectify and try again.""", raise_exception=1)
-
+		if cint(webnotes.conn.get_value("Delivery Note", self.doc.delivery_note, "docstatus")) != 0:
+			msgprint(_("""Invalid Delivery Note. Delivery Note should exist and should be in 
+				draft state. Please rectify and try again."""), raise_exception=1)
+	
+	def validate_items_mandatory(self):
+		rows = [d.item_code for d in self.doclist.get({"parentfield": "item_details"})]
+		if not rows:
+			webnotes.msgprint(_("No Items to Pack"), raise_exception=1)
 
 	def validate_case_nos(self):
 		"""
-			Validate if case nos overlap
-			If they do, recommend next case no.
+			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)
+			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.'",
+			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
 			(from_case_no BETWEEN %(from_case_no)s AND %(to_case_no)s
-			OR to_case_no BETWEEN %(from_case_no)s AND %(to_case_no)s)
+			OR to_case_no BETWEEN %(from_case_no)s AND %(to_case_no)s
+			OR %(from_case_no)s BETWEEN from_case_no AND to_case_no)
 			""", self.doc.fields)
 
 		if res:
-			webnotes.msgprint("""Case No(s). already in use. Please rectify and try again.
-				Recommended <b>From Case No. = %s</b>""" % self.get_recommended_case_no(),
+			webnotes.msgprint(_("""Case No(s) already in use. Please rectify and try again.
+				Recommended <b>From Case No. = %s</b>""") % self.get_recommended_case_no(),
 				raise_exception=1)
 
-
 	def validate_qty(self):
 		"""
 			Check packed qty across packing slips and delivery note
@@ -82,8 +83,9 @@
 		dn_details, ps_item_qty, no_of_cases = self.get_details_for_packing()
 
 		for item in dn_details:
-			new_packed_qty = (flt(ps_item_qty[item['item_code']]) * no_of_cases) + flt(item['packed_qty'])
-			if new_packed_qty > flt(item['qty']):
+			new_packed_qty = (flt(ps_item_qty[item['item_code']]) * no_of_cases) + \
+			 	flt(item['packed_qty'])
+			if new_packed_qty > flt(item['qty']) and no_of_cases:
 				self.recommend_new_qty(item, ps_item_qty, no_of_cases)
 
 
@@ -94,29 +96,26 @@
 			* Item Quantity dict of current packing slip doc
 			* No. of Cases of this packing slip
 		"""
-		item_codes = ", ".join([('"' + d.item_code + '"') for d in
-			self.doclist])
 		
-		items = [d.item_code for d in self.doclist.get({"parentfield": "item_details"})]
+		rows = [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)
+		condition = ""
+		if rows:
+			condition = " and item_code in (%s)" % (", ".join(["%s"]*len(rows)))
 		
 		# 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
+				and ps.delivery_note = dni.parent and psi.item_code=dni.item_code) as packed_qty,
+			stock_uom, item_name
 			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)
-			
-		ps_item_qty = dict([[d.item_code, d.qty] for d in self.doclist])
+			where parent=%s %s 
+			group by item_code""" % ("%s", condition),
+			tuple([self.doc.delivery_note] + rows), as_dict=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
 
 		return res, ps_item_qty, no_of_cases
@@ -136,45 +135,6 @@
 			<b>Recommended quantity for %(item_code)s = %(recommended_qty)s 
 			%(stock_uom)s</b>""" % item, raise_exception=1)
 
-
-	def on_submit(self):
-		"""
-			* Update packed qty for all items
-		"""
-		self.update_packed_qty(event='submit')
-
-
-	def on_cancel(self):
-		"""
-			* Update packed qty for all items
-		"""
-		self.update_packed_qty(event='cancel')
-
-
-	def update_packed_qty(self, event=''):
-		"""
-			Updates packed qty for all items
-		"""
-		if event not in ['submit', 'cancel']:
-			raise Exception('update_packed_quantity can only be called on submit or cancel')
-
-		# Get Delivery Note Items, Item Quantity Dict and No. of Cases for this Packing slip
-		dn_details, ps_item_qty, no_of_cases = self.get_details_for_packing()
-
-		for item in dn_details:
-			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)
-			
-			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']))
-				
-			webnotes.conn.set_value("Delivery Note", self.doc.delivery_note, "modified", now())
-
-
 	def update_item_details(self):
 		"""
 			Fill empty columns in Packing Slip Item
@@ -183,28 +143,12 @@
 			self.doc.from_case_no = self.get_recommended_case_no()
 
 		for d in self.doclist.get({"parentfield": "item_details"}):
-			self.set_item_details(d)
-
-
-	def set_item_details(self, row):
-		res = webnotes.conn.sql("""SELECT item_name, SUM(IFNULL(qty, 0)) as total_qty,
-			IFNULL(packed_qty,	0) as packed_qty, stock_uom
-			FROM `tabDelivery Note Item`
-			WHERE parent=%s AND item_code=%s GROUP BY item_code""",
-			(self.doc.delivery_note, row.item_code), as_dict=1)
-
-		if res and len(res)>0:
-			qty = res[0]['total_qty'] - res[0]['packed_qty']
-			if not row.qty:
-				row.qty = qty >= 0 and qty or 0
-
-		res = webnotes.conn.sql("""SELECT net_weight, weight_uom FROM `tabItem`
-			WHERE name=%s""", row.item_code, as_dict=1)
+			res = webnotes.conn.get_value("Item", d.item_code, 
+				["net_weight", "weight_uom"], as_dict=True)
 			
-		if res and len(res)>0:
-			row.net_weight = res[0]["net_weight"]
-			row.weight_uom = res[0]["weight_uom"]
-
+			if res and len(res)>0:
+				d.net_weight = res["net_weight"]
+				d.weight_uom = res["weight_uom"]
 
 	def get_recommended_case_no(self):
 		"""
@@ -213,5 +157,18 @@
 		"""
 		recommended_case_no = webnotes.conn.sql("""SELECT MAX(to_case_no) FROM `tabPacking Slip`
 			WHERE delivery_note = %(delivery_note)s AND docstatus=1""", self.doc.fields)
-
-		return cint(recommended_case_no[0][0]) + 1
\ No newline at end of file
+		
+		return cint(recommended_case_no[0][0]) + 1
+		
+	def get_items(self):
+		self.doclist = self.doc.clear_table(self.doclist, "item_details", 1)
+		
+		dn_details = self.get_details_for_packing()[0]
+		for item in dn_details:
+			if flt(item.qty) > flt(item.packed_qty):
+				ch = addchild(self.doc, 'item_details', 'Packing Slip Item', self.doclist)
+				ch.item_code = item.item_code
+				ch.item_name = item.item_name
+				ch.stock_uom = item.stock_uom
+				ch.qty = flt(item.qty) - flt(item.packed_qty)
+		self.update_item_details()
\ No newline at end of file
diff --git a/stock/doctype/packing_slip/packing_slip.txt b/stock/doctype/packing_slip/packing_slip.txt
index 32ac16b..f13b971 100644
--- a/stock/doctype/packing_slip/packing_slip.txt
+++ b/stock/doctype/packing_slip/packing_slip.txt
@@ -1,8 +1,8 @@
 [
  {
-  "creation": "2013-03-07 18:50:31", 
+  "creation": "2013-04-11 15:32:24", 
   "docstatus": 0, 
-  "modified": "2013-04-05 15:40:59", 
+  "modified": "2013-04-16 17:33:38", 
   "modified_by": "Administrator", 
   "owner": "Administrator"
  }, 
@@ -132,6 +132,12 @@
  }, 
  {
   "doctype": "DocField", 
+  "fieldname": "get_items", 
+  "fieldtype": "Button", 
+  "label": "Get Items"
+ }, 
+ {
+  "doctype": "DocField", 
   "fieldname": "item_details", 
   "fieldtype": "Table", 
   "label": "Items", 
diff --git a/stock/doctype/packing_slip_item/packing_slip_item.txt b/stock/doctype/packing_slip_item/packing_slip_item.txt
index a9d2fdf..b186f40 100644
--- a/stock/doctype/packing_slip_item/packing_slip_item.txt
+++ b/stock/doctype/packing_slip_item/packing_slip_item.txt
@@ -1,8 +1,8 @@
 [
  {
-  "creation": "2013-03-07 11:42:59", 
+  "creation": "2013-04-08 13:10:16", 
   "docstatus": 0, 
-  "modified": "2013-04-05 16:06:40", 
+  "modified": "2013-04-11 15:06:05", 
   "modified_by": "Administrator", 
   "owner": "Administrator"
  }, 
@@ -70,7 +70,7 @@
   "fieldtype": "Float", 
   "label": "Net Weight", 
   "print_width": "100px", 
-  "read_only": 1, 
+  "read_only": 0, 
   "width": "100px"
  }, 
  {
@@ -80,7 +80,7 @@
   "label": "Weight UOM", 
   "options": "UOM", 
   "print_width": "100px", 
-  "read_only": 1, 
+  "read_only": 0, 
   "width": "100px"
  }, 
  {
@@ -95,6 +95,7 @@
   "fieldname": "dn_detail", 
   "fieldtype": "Data", 
   "hidden": 1, 
-  "label": "DN Detail"
+  "label": "DN Detail", 
+  "read_only": 0
  }
 ]
\ No newline at end of file
diff --git a/stock/doctype/serial_no/serial_no.py b/stock/doctype/serial_no/serial_no.py
index 65bd2dd..bbf55b3 100644
--- a/stock/doctype/serial_no/serial_no.py
+++ b/stock/doctype/serial_no/serial_no.py
@@ -79,7 +79,6 @@
 		values = [{
 			'item_code'				: self.doc.item_code,
 			'warehouse'				: self.doc.warehouse,
-			'transaction_date'		: nowdate(),
 			'posting_date'			: self.doc.purchase_date or (self.doc.creation and self.doc.creation.split(' ')[0]) or nowdate(),
 			'posting_time'			: self.doc.purchase_time or '00:00',
 			'voucher_type'			: 'Serial No',
diff --git a/stock/doctype/stock_ledger/stock_ledger.py b/stock/doctype/stock_ledger/stock_ledger.py
index 469c94b..3c83de3 100644
--- a/stock/doctype/stock_ledger/stock_ledger.py
+++ b/stock/doctype/stock_ledger/stock_ledger.py
@@ -84,7 +84,6 @@
 		item_details = webnotes.conn.sql("""select item_group, warranty_period 
 			from `tabItem` where name = '%s' and (ifnull(end_of_life,'')='' or 
 			end_of_life = '0000-00-00' or end_of_life > now()) """ %(d.item_code), as_dict=1)
-		webnotes.errprint([d.item_code, d.valuation_rate])
 		
 		s.purchase_document_type	=	obj.doc.doctype
 		s.purchase_document_no		=	obj.doc.name
diff --git a/website/doctype/website_settings/website_settings.txt b/website/doctype/website_settings/website_settings.txt
index a39144c..0ebc75b 100644
--- a/website/doctype/website_settings/website_settings.txt
+++ b/website/doctype/website_settings/website_settings.txt
@@ -1,8 +1,8 @@
 [
  {
-  "creation": "2013-03-07 11:55:11", 
+  "creation": "2013-03-26 06:51:18", 
   "docstatus": 0, 
-  "modified": "2013-03-13 16:25:22", 
+  "modified": "2013-04-17 11:51:24", 
   "modified_by": "Administrator", 
   "owner": "Administrator"
  }, 
@@ -50,7 +50,7 @@
   "fieldtype": "Link", 
   "label": "Home Page", 
   "options": "Web Page", 
-  "reqd": 1
+  "reqd": 0
  }, 
  {
   "description": "The name of your company / website as you want to appear on browser title bar. All pages will have this as the prefix to the title.", 
@@ -240,13 +240,6 @@
   "create": 1, 
   "doctype": "DocPerm", 
   "permlevel": 0, 
-  "role": "System Manager", 
-  "write": 1
- }, 
- {
-  "create": 1, 
-  "doctype": "DocPerm", 
-  "permlevel": 0, 
   "role": "Website Manager", 
   "write": 1
  }, 
diff --git a/website/helpers/sitemap.py b/website/helpers/sitemap.py
index 201865a..c8b6fd0 100644
--- a/website/helpers/sitemap.py
+++ b/website/helpers/sitemap.py
@@ -14,25 +14,40 @@
 	import urllib, os
 	import webnotes
 	import webnotes.webutils
+	from webnotes.utils import nowdate
 
 	# settings
-	max_doctypes = 10
 	max_items = 1000
+	count = 0
 	
 	site_map = ''
-	page_list = []
-	
 	if domain:
-		# list of all pages in web cache
-		for doctype in webnotes.webutils.page_map:
-			d = webnotes.webutils.page_map[doctype];
+		today = nowdate()
+		
+		# generated pages
+		for doctype, opts in webnotes.webutils.get_generators().items():
 			pages = webnotes.conn.sql("""select page_name, `modified`
 				from `tab%s` where ifnull(%s,0)=1
-				order by modified desc""" % (doctype, d.condition_field))
+				order by modified desc""" % (doctype, opts.get("condition_field")))
 		
 			for p in pages:
+				if count >= max_items: break
 				page_url = os.path.join(domain, urllib.quote(p[0]))
 				modified = p[1].strftime('%Y-%m-%d')
 				site_map += link_xml % (page_url, modified)
+				count += 1
+				
+			if count >= max_items: break
+		
+		# standard pages
+		for page, opts in webnotes.get_config()["web"]["pages"].items():
+			if "no_cache" in opts:
+				continue
+			
+			if count >= max_items: break
+			page_url = os.path.join(domain, urllib.quote(page))
+			modified = today
+			site_map += link_xml % (page_url, modified)
+			count += 1
 
-		return frame_xml % site_map
+	return frame_xml % site_map