Merge branch 'develop' of github.com:frappe/erpnext into v4-hotfix
diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.json b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.json
index eff6e6d..d0757fd 100644
--- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.json
+++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.json
@@ -2,7 +2,7 @@
  "allow_copy": 1, 
  "allow_email": 1, 
  "allow_print": 1, 
- "creation": "2013-01-10 16:34:05.000000", 
+ "creation": "2013-01-10 16:34:05", 
  "docstatus": 0, 
  "doctype": "DocType", 
  "fields": [
@@ -10,6 +10,7 @@
    "description": "Select account head of the bank where cheque was deposited.", 
    "fieldname": "bank_account", 
    "fieldtype": "Link", 
+   "in_list_view": 1, 
    "label": "Bank Account", 
    "options": "Account", 
    "permlevel": 0, 
@@ -19,6 +20,7 @@
    "fieldname": "company", 
    "fieldtype": "Link", 
    "hidden": 1, 
+   "in_list_view": 1, 
    "label": "Company", 
    "options": "Company", 
    "permlevel": 0, 
@@ -28,6 +30,7 @@
   {
    "fieldname": "from_date", 
    "fieldtype": "Date", 
+   "in_list_view": 1, 
    "label": "From Date", 
    "permlevel": 0, 
    "reqd": 1
@@ -35,14 +38,22 @@
   {
    "fieldname": "to_date", 
    "fieldtype": "Date", 
+   "in_list_view": 1, 
    "label": "To Date", 
    "permlevel": 0, 
    "reqd": 1
   }, 
   {
-   "fieldname": "get_non_reconciled_entries", 
+   "fieldname": "include_reconciled_entries", 
+   "fieldtype": "Check", 
+   "in_list_view": 1, 
+   "label": "Include Reconciled Entries", 
+   "permlevel": 0
+  }, 
+  {
+   "fieldname": "get_relevant_entries", 
    "fieldtype": "Button", 
-   "label": "Get Non Reconciled Entries", 
+   "label": "Get Relevant Entries", 
    "options": "get_details", 
    "permlevel": 0
   }, 
@@ -74,7 +85,7 @@
  "icon": "icon-check", 
  "idx": 1, 
  "issingle": 1, 
- "modified": "2013-07-05 14:26:22.000000", 
+ "modified": "2014-05-06 16:26:08.984595", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Bank Reconciliation", 
diff --git a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py
index 8bf1172..a411898 100644
--- a/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py
+++ b/erpnext/accounts/doctype/bank_reconciliation/bank_reconciliation.py
@@ -3,7 +3,7 @@
 
 from __future__ import unicode_literals
 import frappe
-from frappe.utils import cstr, flt, getdate, nowdate
+from frappe.utils import flt, getdate, nowdate
 from frappe import msgprint, _
 from frappe.model.document import Document
 
@@ -13,29 +13,34 @@
 			msgprint("Bank Account, From Date and To Date are Mandatory")
 			return
 
+		condition = ""
+		if not self.include_reconciled_entries:
+			condition = "and ifnull(clearance_date, '') in ('', '0000-00-00')"
+
+
 		dl = frappe.db.sql("""select t1.name, t1.cheque_no, t1.cheque_date, t2.debit,
-				t2.credit, t1.posting_date, t2.against_account
+				t2.credit, t1.posting_date, t2.against_account, t1.clearance_date
 			from
 				`tabJournal Voucher` t1, `tabJournal Voucher Detail` t2
 			where
 				t2.parent = t1.name and t2.account = %s
-				and (clearance_date is null or clearance_date = '0000-00-00' or clearance_date = '')
-				and t1.posting_date >= %s and t1.posting_date <= %s and t1.docstatus=1""",
-				(self.bank_account, self.from_date, self.to_date))
+				and t1.posting_date >= %s and t1.posting_date <= %s and t1.docstatus=1 %s""" %
+				('%s', '%s', '%s', condition), (self.bank_account, self.from_date, self.to_date), as_dict=1)
 
 		self.set('entries', [])
 		self.total_amount = 0.0
 
 		for d in dl:
 			nl = self.append('entries', {})
-			nl.posting_date = cstr(d[5])
-			nl.voucher_id = cstr(d[0])
-			nl.cheque_number = cstr(d[1])
-			nl.cheque_date = cstr(d[2])
-			nl.debit = flt(d[3])
-			nl.credit = flt(d[4])
-			nl.against_account = cstr(d[6])
-			self.total_amount += flt(flt(d[4]) - flt(d[3]))
+			nl.posting_date = d.posting_date
+			nl.voucher_id = d.name
+			nl.cheque_number = d.cheque_no
+			nl.cheque_date = d.cheque_date
+			nl.debit = d.debit
+			nl.credit = d.credit
+			nl.against_account = d.against_account
+			nl.clearance_date = d.clearance_date
+			self.total_amount += flt(d.debit) - flt(d.credit)
 
 	def update_details(self):
 		vouchers = []
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index 229e230..41b63c3 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -49,32 +49,6 @@
 	dialog.show();
 }
 
-cur_frm.cscript.has_special_chars = function(t) {
-  var iChars = "!@#$%^*+=-[]\\\';,/{}|\":<>?";
-  for (var i = 0; i < t.length; i++) {
-    if (iChars.indexOf(t.charAt(i)) != -1) {
-      return true;
-    }
-  }
-  return false;
-}
-
-cur_frm.cscript.company_name = function(doc){
-	if(doc.company_name && cur_frm.cscript.has_special_chars(doc.company_name)){
-		msgprint(__("Special Characters not allowed in Company Name"));
-		doc.company_name = '';
-		refresh_field('company_name');
-	}
-}
-
-cur_frm.cscript.abbr = function(doc){
-	if(doc.abbr && cur_frm.cscript.has_special_chars(doc.abbr)){
-		msgprint(__("Special Characters not allowed in Abbreviation"));
-		doc.abbr = '';
-		refresh_field('abbr');
-	}
-}
-
 cur_frm.fields_dict.default_bank_account.get_query = function(doc) {
 	return{
 		filters: [
diff --git a/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.js
index 9852eec..476530b 100644
--- a/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.js
+++ b/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.js
@@ -3,12 +3,12 @@
 
 frappe.provide("erpnext.support");
 
-frappe.ui.form.on_change("Maintenance Schedule", "customer", function(frm) { 
+frappe.ui.form.on_change("Maintenance Schedule", "customer", function(frm) {
 	erpnext.utils.get_party_details(frm) });
-frappe.ui.form.on_change("Maintenance Schedule", "customer_address", 
+frappe.ui.form.on_change("Maintenance Schedule", "customer_address",
 	erpnext.utils.get_address_display);
-frappe.ui.form.on_change("Maintenance Schedule", "contact_person", 
-	erpnext.utils.get_contact_details);	
+frappe.ui.form.on_change("Maintenance Schedule", "contact_person",
+	erpnext.utils.get_contact_details);
 
 // TODO commonify this code
 erpnext.support.MaintenanceSchedule = frappe.ui.form.Controller.extend({
@@ -16,7 +16,7 @@
 		var me = this;
 
 		if (this.frm.doc.docstatus === 0) {
-			this.frm.add_custom_button(__('From Sales Order'), 
+			this.frm.add_custom_button(__('From Sales Order'),
 				function() {
 					frappe.model.map_current_doc({
 						method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_schedule",
@@ -38,16 +38,52 @@
 			});
 		}
 	},
+
+	start_date: function(doc, cdt, cdn) {
+		this.set_no_of_visits(doc, cdt, cdn);
+	},
+
+	end_date: function(doc, cdt, cdn) {
+		this.set_no_of_visits(doc, cdt, cdn);
+	},
+
+	periodicity: function(doc, cdt, cdn) {
+		this.set_no_of_visits(doc, cdt, cdn);
+	},
+
+	set_no_of_visits: function(doc, cdt, cdn) {
+		var item = frappe.get_doc(cdt, cdn);
+
+		if (item.start_date && item.end_date && item.periodicity) {
+			if(item.start_date > item.end_date) {
+				msgprint(__("Row {0}:Start Date must be before End Date", [item.idx]));
+				return;
+			}
+
+			var date_diff = frappe.datetime.get_diff(item.end_date, item.start_date) + 1;
+
+			var days_in_period = {
+				"Weekly": 7,
+				"Monthly": 30,
+				"Quarterly": 91,
+				"Half Yearly": 182,
+				"Yearly": 365
+			}
+
+			var no_of_visits = cint(date_diff / days_in_period[item.periodicity]);
+			frappe.model.set_value(item.doctype, item.name, "no_of_visits", no_of_visits);
+		}
+	},
 });
 
 $.extend(cur_frm.cscript, new erpnext.support.MaintenanceSchedule({frm: cur_frm}));
 
 cur_frm.cscript.onload = function(doc, dt, dn) {
   if(!doc.status) set_multiple(dt,dn,{status:'Draft'});
-  
+
   if(doc.__islocal){
     set_multiple(dt,dn,{transaction_date:get_today()});
-  }   
+  }
 }
 
 cur_frm.fields_dict['customer_address'].get_query = function(doc, cdt, cdn) {
@@ -62,7 +98,7 @@
 	}
 }
 
-//
+
 cur_frm.fields_dict['item_maintenance_detail'].grid.get_field('item_code').get_query = function(doc, cdt, cdn) {
 	return {
 		filters:{ 'is_service_item': "Yes" }
@@ -73,25 +109,11 @@
 	var fname = cur_frm.cscript.fname;
 	var d = locals[cdt][cdn];
 	if (d.item_code) {
-		return get_server_fields('get_item_details', d.item_code, 'item_maintenance_detail', 
+		return get_server_fields('get_item_details', d.item_code, 'item_maintenance_detail',
 			doc, cdt, cdn, 1);
 	}
 }
 
-cur_frm.cscript.periodicity = function(doc, cdt, cdn){
-	var d = locals[cdt][cdn];
-	if(d.start_date && d.end_date) {
-		arg = {}
-		arg.start_date = d.start_date;
-		arg.end_date = d.end_date;
-		arg.periodicity = d.periodicity;
-		return get_server_fields('get_no_of_visits', docstring(arg), 
-			'item_maintenance_detail', doc, cdt, cdn, 1);
-	} else {
-		msgprint(__("Please enter Start Date and End Date"));
-	}
-}
-
 cur_frm.cscript.generate_schedule = function(doc, cdt, cdn) {
 	if (!doc.__islocal) {
 		return $c('runserverobj', args={'method':'generate_schedule', 'docs':doc},
diff --git a/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.py
index 74d0e2e..a0eba19 100644
--- a/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.py
+++ b/erpnext/support/doctype/maintenance_schedule/maintenance_schedule.py
@@ -133,40 +133,22 @@
 
 		return schedule_date
 
-	def validate_period(self, arg):
-		args = eval(arg)
-		if getdate(args['start_date']) >= getdate(args['end_date']):
-			throw(_("Start date should be less than end date."))
+	def validate_dates_with_periodicity(self):
+		for d in self.get("item_maintenance_detail"):
+			if d.start_date and d.end_date and d.periodicity:
+				date_diff = (getdate(d.end_date) - getdate(d.start_date)).days + 1
+				days_in_period = {
+					"Weekly": 7,
+					"Monthly": 30,
+					"Quarterly": 90,
+					"Half Yearly": 180,
+					"Yearly": 365
+				}
 
-		period = (getdate(args['end_date']) - getdate(args['start_date'])).days + 1
-
-		if (args['periodicity'] == 'Yearly' or args['periodicity'] == 'Half Yearly' or
-			args['periodicity'] == 'Quarterly') and period < 90:
-			throw(_("Period is too short"))
-		elif args['periodicity'] == 'Monthly' and period < 30:
-			throw(_("Period is too short"))
-		elif args['periodicity'] == 'Weekly' and period < 7:
-			throw(_("Period is too short"))
-
-	def get_no_of_visits(self, arg):
-		args = eval(arg)
-		self.validate_period(arg)
-		period = (getdate(args['end_date']) - getdate(args['start_date'])).days + 1
-		count = 0
-
-		if args['periodicity'] == 'Weekly':
-			count = period/7
-		elif args['periodicity'] == 'Monthly':
-			count = period/30
-		elif args['periodicity'] == 'Quarterly':
-			count = period/91
-		elif args['periodicity'] == 'Half Yearly':
-			count = period/182
-		elif args['periodicity'] == 'Yearly':
-			count = period/365
-
-		ret = {'no_of_visits' : count}
-		return ret
+				if date_diff < days_in_period[d.periodicity]:
+					throw(_("Row {0}: To set {1} periodicity, difference between from and to date \
+						must be greater than or equal to {2}")
+						.format(d.idx, d.periodicity, days_in_period[d.periodicity]))
 
 	def validate_maintenance_detail(self):
 		if not self.get('item_maintenance_detail'):
@@ -196,6 +178,7 @@
 
 	def validate(self):
 		self.validate_maintenance_detail()
+		self.validate_dates_with_periodicity()
 		self.validate_sales_order()
 
 	def on_update(self):