Suggested Changes to School (#6223)

* Linkage of academic term to academic year

* School improvements. Modifications to Academic Term, Assessment, Fees, Student Batch, Student Group. Addition of Grading System.

* Removed Grading System from Assessment and put it on Program

* Removed the field Grading System from Program and added it back to Assessment. Added some validations for dates in controller of Academic Term and Academic Year

* Added validation comparing term start dates with academic year start dates and term end dates with academic year end dates where both are available.

* Renamed Grading System to Grading Structure. Implemented the code in Assessment.js to derive the Grade Code from the result entered for the student. Assumes that result is always a number. Will rename the field result in Results to score.

* Added validation to check if any grade intervals were overlapping when a Grading Structure is being saved.

* Corrections to error in autonaming for Academic Term

* Correction in white_list method get_grade in Assessment. Solves problem with grades not being derived when the score is at the boundaries of a grade interval

* Correction to setup_wizard.py to make sure that creation of academic terms in create_academic_term includes the academic_year which is now mandatory

* Corrections to test_records.json for doctype Academic Term

* Correction of test_records.json in doctype Student Groups

* Correction of test_records.json for doctype Student Group 2

* Correction to test_course_schedule.py in doctype Course Schedule

* More corrections to test_course_schedule.py in doctype Course Schedule

* Corrections to test_course_schedule.py

* Updates to Student DocType. Enrollment date, Nationality

* Linkage of academic term to academic year

* School improvements. Modifications to Academic Term, Assessment, Fees, Student Batch, Student Group. Addition of Grading System.

* Removed Grading System from Assessment and put it on Program

* Removed the field Grading System from Program and added it back to Assessment. Added some validations for dates in controller of Academic Term and Academic Year

* Added validation comparing term start dates with academic year start dates and term end dates with academic year end dates where both are available.

* Renamed Grading System to Grading Structure. Implemented the code in Assessment.js to derive the Grade Code from the result entered for the student. Assumes that result is always a number. Will rename the field result in Results to score.

* Added validation to check if any grade intervals were overlapping when a Grading Structure is being saved.

* Corrections to error in autonaming for Academic Term
diff --git a/erpnext/config/schools.py b/erpnext/config/schools.py
index 5e73fce..857a422 100644
--- a/erpnext/config/schools.py
+++ b/erpnext/config/schools.py
@@ -122,6 +122,10 @@
 				},
 				{
 					"type": "doctype",
+					"name": "Grading Structure"
+				},
+				{
+					"type": "doctype",
 					"name": "Program"
 				},
 				{
diff --git a/erpnext/schools/doctype/academic_term/academic_term.json b/erpnext/schools/doctype/academic_term/academic_term.json
index 9d9c9e0..ca10ebf 100644
--- a/erpnext/schools/doctype/academic_term/academic_term.json
+++ b/erpnext/schools/doctype/academic_term/academic_term.json
@@ -2,7 +2,7 @@
  "allow_copy": 0, 
  "allow_import": 1, 
  "allow_rename": 1, 
- "autoname": "field:term_name", 
+ "autoname": "field:title", 
  "beta": 0, 
  "creation": "2015-09-08 17:19:19.158228", 
  "custom": 0, 
@@ -15,6 +15,32 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
+   "fieldname": "academic_year", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 0, 
+   "label": "Academic Year", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Academic Year", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
    "fieldname": "term_name", 
    "fieldtype": "Data", 
    "hidden": 0, 
@@ -31,6 +57,81 @@
    "print_hide_if_no_value": 0, 
    "read_only": 0, 
    "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "term_start_date", 
+   "fieldtype": "Date", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 1, 
+   "label": "Term Start Date", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 1, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "term_end_date", 
+   "fieldtype": "Date", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 1, 
+   "label": "Term End Date", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 1, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "title", 
+   "fieldtype": "Data", 
+   "hidden": 1, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 0, 
+   "label": "Title", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
@@ -47,7 +148,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2016-07-25 05:24:23.032319", 
+ "modified": "2016-08-27 23:02:03.565866", 
  "modified_by": "Administrator", 
  "module": "Schools", 
  "name": "Academic Term", 
@@ -78,7 +179,8 @@
  "quick_entry": 1, 
  "read_only": 0, 
  "read_only_onload": 0, 
- "sort_field": "modified", 
+ "sort_field": "name", 
  "sort_order": "DESC", 
+ "title_field": "title", 
  "track_seen": 0
 }
\ No newline at end of file
diff --git a/erpnext/schools/doctype/academic_term/academic_term.py b/erpnext/schools/doctype/academic_term/academic_term.py
index 1a4526b..891feb8 100644
--- a/erpnext/schools/doctype/academic_term/academic_term.py
+++ b/erpnext/schools/doctype/academic_term/academic_term.py
@@ -4,7 +4,35 @@
 
 from __future__ import unicode_literals
 import frappe
+from frappe import msgprint, _
+from frappe.utils import get_datetime, get_datetime_str
 from frappe.model.document import Document
 
 class AcademicTerm(Document):
-	pass
+    def autoname(self):
+        self.name = self.academic_year + " ({})".format(self.term_name) if self.term_name else ""
+        
+    def validate(self):
+        #Check if entry with same academic_year and the term_name already exists
+        validate_duplication(self)
+        self.title = self.academic_year + " ({})".format(self.term_name) if self.term_name else ""
+        
+        #Check that start of academic year is earlier than end of academic year
+        if self.term_start_date and self.term_end_date and self.term_start_date > self.term_end_date:
+            frappe.throw(_("The Term End Date cannot be earlier than the Term Start Date. Please correct the dates and try again."))
+        
+        """Check that the start of the term is not before the start of the academic year and end of term is not after 
+            the end of the academic year"""
+        year = frappe.get_doc("Academic Year",self.academic_year)
+        if self.term_start_date and get_datetime_str(year.year_start_date) and (self.term_start_date < get_datetime_str(year.year_start_date)):
+            frappe.throw(_("The Term Start Date cannot be earlier than the Year Start Date of the Academic Year to which the term is linked (Academic Year {}). Please correct the dates and try again.").format(self.academic_year))
+        
+        if self.term_end_date and get_datetime_str(year.year_end_date) and (self.term_end_date > get_datetime_str(year.year_end_date)):
+            frappe.throw(_("The Term End Date cannot be later than the Year End Date of the Academic Year to which the term is linked (Academic Year {}). Please correct the dates and try again.").format(self.academic_year))
+
+
+def validate_duplication(self):
+    term = frappe.db.sql("""select name from `tabAcademic Term` where academic_year= %s and term_name= %s 
+    and docstatus<2 and name != %s""", (self.academic_year, self.term_name, self.name))
+    if term:
+        frappe.throw(_("An academic term with this 'Academic Year' {0} and 'Term Name' {1} already exists. Please modify these entries and try again.").format(self.academic_year,self.term_name))
diff --git a/erpnext/schools/doctype/academic_term/test_records.json b/erpnext/schools/doctype/academic_term/test_records.json
index 9807221..2d84383 100644
--- a/erpnext/schools/doctype/academic_term/test_records.json
+++ b/erpnext/schools/doctype/academic_term/test_records.json
@@ -1,11 +1,17 @@
 [
-	{
-		"term_name": "_Test Academic Term"
-	},
-	{
-		"term_name": "_Test Academic Term 1"
-	},
-	{
-		"term_name": "_Test Academic Term 2"
-	}
-]
\ No newline at end of file
+    {
+        "doctype": "Academic Term",
+        "academic_year": "2014-2015",
+        "term_name": "_Test Academic Term"
+    },
+    {
+        "doctype": "Academic Term",
+        "academic_year": "2014-2015",
+        "term_name": "_Test Academic Term 1"
+    },
+    {
+        "doctype": "Academic Term",
+        "academic_year": "2014-2015",
+        "term_name": "_Test Academic Term 2"
+    }
+]    
\ No newline at end of file
diff --git a/erpnext/schools/doctype/academic_year/academic_year.py b/erpnext/schools/doctype/academic_year/academic_year.py
index 4b955de..f2858a4 100644
--- a/erpnext/schools/doctype/academic_year/academic_year.py
+++ b/erpnext/schools/doctype/academic_year/academic_year.py
@@ -4,7 +4,11 @@
 
 from __future__ import unicode_literals
 import frappe
+from frappe import msgprint, _
 from frappe.model.document import Document
 
 class AcademicYear(Document):
-	pass
+    def validate(self):
+        #Check that start of academic year is earlier than end of academic year
+        if self.year_start_date and self.year_end_date and self.year_start_date > self.year_end_date:
+            frappe.throw(_("The Year End Date cannot be earlier than the Year Start Date. Please correct the dates and try again."))
diff --git a/erpnext/schools/doctype/assessment/assessment.js b/erpnext/schools/doctype/assessment/assessment.js
index 799ae7b..efadbd6 100644
--- a/erpnext/schools/doctype/assessment/assessment.js
+++ b/erpnext/schools/doctype/assessment/assessment.js
@@ -28,4 +28,24 @@
 			});
 		}
 	}
+});
+
+frappe.ui.form.on("Assessment Result" ,{
+	result : function(frm, cdt, cdn) {
+		if(frm.doc.grading_structure){
+			var assessment_result = locals[cdt][cdn];
+			frappe.call({
+				method:"erpnext.schools.doctype.assessment.assessment.get_grade",
+				args:{
+					grading_structure: frm.doc.grading_structure,
+					result: assessment_result.result
+				},
+				callback: function(r){
+					if(r.message){
+						frappe.model.set_value(cdt, cdn, 'grade', r.message);
+					}
+				}
+			});
+		}
+	}
 });
\ No newline at end of file
diff --git a/erpnext/schools/doctype/assessment/assessment.json b/erpnext/schools/doctype/assessment/assessment.json
index 30ac1ed..e978d08 100644
--- a/erpnext/schools/doctype/assessment/assessment.json
+++ b/erpnext/schools/doctype/assessment/assessment.json
@@ -91,6 +91,32 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
+   "fieldname": "grading_structure", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 0, 
+   "label": "Grading Structure", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Grading Structure", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
    "fieldname": "course", 
    "fieldtype": "Link", 
    "hidden": 0, 
@@ -506,7 +532,7 @@
  "istable": 0, 
  "max_attachments": 0, 
  "menu_index": 0, 
- "modified": "2016-08-05 04:57:41.018614", 
+ "modified": "2016-08-27 14:18:51.852078", 
  "modified_by": "Administrator", 
  "module": "Schools", 
  "name": "Assessment", 
diff --git a/erpnext/schools/doctype/assessment/assessment.py b/erpnext/schools/doctype/assessment/assessment.py
index a23d5cc..de6a653 100644
--- a/erpnext/schools/doctype/assessment/assessment.py
+++ b/erpnext/schools/doctype/assessment/assessment.py
@@ -8,39 +8,56 @@
 from frappe import _
 
 class Assessment(Document):
-	def validate(self):
-		self.validate_overlap()
-	
-	def validate_overlap(self):
-		"""Validates overlap for Student Group, Supervisor, Room"""
+    def validate(self):
+        self.validate_overlap()
+    
+    def validate_overlap(self):
+        """Validates overlap for Student Group, Supervisor, Room"""
 
-		from erpnext.schools.utils import validate_overlap_for
+        from erpnext.schools.utils import validate_overlap_for
 
-		validate_overlap_for(self, "Assessment", "student_group")
-		validate_overlap_for(self, "Course Schedule", "student_group" )
-		
-		if self.room:
-			validate_overlap_for(self, "Assessment", "room")
-			validate_overlap_for(self, "Course Schedule", "room")
+        validate_overlap_for(self, "Assessment", "student_group")
+        validate_overlap_for(self, "Course Schedule", "student_group" )
+        
+        if self.room:
+            validate_overlap_for(self, "Assessment", "room")
+            validate_overlap_for(self, "Course Schedule", "room")
 
-		if self.supervisor:
-			validate_overlap_for(self, "Assessment", "supervisor")
-			validate_overlap_for(self, "Course Schedule", "instructor", self.supervisor)
+        if self.supervisor:
+            validate_overlap_for(self, "Assessment", "supervisor")
+            validate_overlap_for(self, "Course Schedule", "instructor", self.supervisor)
 
 def get_assessment_list(doctype, txt, filters, limit_start, limit_page_length=20):
-	user = frappe.session.user
-	student = frappe.db.sql("select name from `tabStudent` where student_email_id= %s", user)
-	if student:
-		return frappe. db.sql('''select course, schedule_date, from_time, to_time, sgs.name from `tabAssessment` as assessment, 
-			`tabStudent Group Student` as sgs where assessment.student_group = sgs.parent and sgs.student = %s and assessment.docstatus=1
-			order by assessment.name asc limit {0} , {1}'''
-			.format(limit_start, limit_page_length), student, as_dict = True)
+    user = frappe.session.user
+    student = frappe.db.sql("select name from `tabStudent` where student_email_id= %s", user)
+    if student:
+        return frappe. db.sql('''select course, schedule_date, from_time, to_time, sgs.name from `tabAssessment` as assessment, 
+            `tabStudent Group Student` as sgs where assessment.student_group = sgs.parent and sgs.student = %s and assessment.docstatus=1
+            order by assessment.name asc limit {0} , {1}'''
+            .format(limit_start, limit_page_length), student, as_dict = True)
 
 def get_list_context(context=None):
-	return {
-		"show_sidebar": True,
-		'no_breadcrumbs': True,
-		"title": _("Assessment Schedule"),
-		"get_list": get_assessment_list,
-		"row_template": "templates/includes/assessment/assessment_row.html"
-	}
+    return {
+        "show_sidebar": True,
+        'no_breadcrumbs': True,
+        "title": _("Assessment Schedule"),
+        "get_list": get_assessment_list,
+        "row_template": "templates/includes/assessment/assessment_row.html"
+    }
+
+@frappe.whitelist()
+def get_grade(grading_structure, result):
+    grade = frappe.db.sql("""select gi.from_score, gi.to_score, gi.grade_code, gi.grade_description 
+        from `tabGrading Structure` as gs, `tabGrade Interval` as gi 
+        where gs.name = gi.parent and gs.name = %(grading_structure)s and gi.from_score <= %(result)s 
+        and gi.to_score >= %(result)s""".format(), 
+        {
+            "grading_structure":grading_structure,
+            "result": result
+        },
+        as_dict=True)
+    
+    return grade[0].grade_code if grade else ""
+
+def validate_grade(score, grade):
+    pass
\ No newline at end of file
diff --git a/erpnext/schools/doctype/assessment_result/assessment_result.json b/erpnext/schools/doctype/assessment_result/assessment_result.json
index 19339eb..91e580d 100644
--- a/erpnext/schools/doctype/assessment_result/assessment_result.json
+++ b/erpnext/schools/doctype/assessment_result/assessment_result.json
@@ -109,6 +109,31 @@
    "search_index": 0, 
    "set_only_once": 0, 
    "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "grade", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 1, 
+   "label": "Grade", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 1, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
   }
  ], 
  "hide_heading": 0, 
@@ -121,7 +146,7 @@
  "issingle": 0, 
  "istable": 1, 
  "max_attachments": 0, 
- "modified": "2016-08-01 10:37:23.571679", 
+ "modified": "2016-08-27 12:15:01.923000", 
  "modified_by": "Administrator", 
  "module": "Schools", 
  "name": "Assessment Result", 
diff --git a/erpnext/schools/doctype/course_schedule/test_course_schedule.py b/erpnext/schools/doctype/course_schedule/test_course_schedule.py
index b527303..e9fce4b 100644
--- a/erpnext/schools/doctype/course_schedule/test_course_schedule.py
+++ b/erpnext/schools/doctype/course_schedule/test_course_schedule.py
@@ -24,27 +24,27 @@
 		cs1 = make_course_schedule_test_record(simulate= True)
 		
 		cs2 = make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time, 
-			student_group="TC2-TP-2014-2015-_Test Academic Term", room="RM0002", do_not_save= 1)
+			student_group="TC2-TP-2014-2015-2014-2015 (_Test Academic Term)", room="RM0002", do_not_save= 1)
 		self.assertRaises(OverlapError, cs2.save)
 
 	def test_room_conflict(self):
 		cs1 = make_course_schedule_test_record(simulate= True)
 		
 		cs2 = make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time, 
-			student_group="TC2-TP-2014-2015-_Test Academic Term", instructor="_T-Instructor-00002", do_not_save= 1)
+			student_group="TC2-TP-2014-2015-2014-2015 (_Test Academic Term)", instructor="_T-Instructor-00002", do_not_save= 1)
 		self.assertRaises(OverlapError, cs2.save)
 		
 	def test_no_conflict(self):
 		cs1 = make_course_schedule_test_record(simulate= True)
 		
 		make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time, 
-			student_group="TC2-TP-2014-2015-_Test Academic Term", instructor="_T-Instructor-00002", room="RM0002")
+			student_group="TC2-TP-2014-2015-2014-2015 (_Test Academic Term)", instructor="_T-Instructor-00002", room="RM0002")
 
 def make_course_schedule_test_record(**args):
 	args = frappe._dict(args)
 
 	course_schedule = frappe.new_doc("Course Schedule")
-	course_schedule.student_group = args.student_group or "TC-TP-2014-2015-_Test Academic Term"
+	course_schedule.student_group = args.student_group or "TC-TP-2014-2015-2014-2015 (_Test Academic Term)"
 	course_schedule.course = args.course or "_Test Course"
 	course_schedule.instructor = args.instructor or "_T-Instructor-00001"
 	course_schedule.room = args.room or "RM0001"
diff --git a/erpnext/schools/doctype/fees/fees.js b/erpnext/schools/doctype/fees/fees.js
index 22c6d8a..7c35de4 100644
--- a/erpnext/schools/doctype/fees/fees.js
+++ b/erpnext/schools/doctype/fees/fees.js
@@ -2,6 +2,25 @@
 cur_frm.add_fetch("student", "title", "student_name");
 
 frappe.ui.form.on("Fees", {
+	
+	onload: function(frm){
+		cur_frm.set_query("academic_term",function(){
+			return{
+				"filters":{
+					"academic_year": (frm.doc.academic_year)
+				}
+			};
+		});
+		
+		cur_frm.set_query("fee_structure",function(){
+			return{
+				"filters":{
+					"academic_term": (frm.doc.academic_term)
+				}
+			};
+		});
+	},
+	
 	refresh: function(frm) {
 		if (frm.doc.docstatus === 1 && (frm.doc.total_amount > frm.doc.paid_amount)) {
 			frm.add_custom_button(__("Collect Fees"), function() {
diff --git a/erpnext/schools/doctype/fees/fees.json b/erpnext/schools/doctype/fees/fees.json
index ce911ad..5682ef9 100644
--- a/erpnext/schools/doctype/fees/fees.json
+++ b/erpnext/schools/doctype/fees/fees.json
@@ -41,17 +41,17 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
-   "fieldname": "academic_term", 
+   "fieldname": "academic_year", 
    "fieldtype": "Link", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
    "in_filter": 0, 
    "in_list_view": 0, 
-   "label": "Academic Term", 
+   "label": "Academic Year", 
    "length": 0, 
    "no_copy": 0, 
-   "options": "Academic Term", 
+   "options": "Academic Year", 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
@@ -67,17 +67,17 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
-   "fieldname": "academic_year", 
+   "fieldname": "academic_term", 
    "fieldtype": "Link", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
    "in_filter": 0, 
    "in_list_view": 0, 
-   "label": "Academic Year", 
+   "label": "Academic Term", 
    "length": 0, 
    "no_copy": 0, 
-   "options": "Academic Year", 
+   "options": "Academic Term", 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
@@ -480,7 +480,7 @@
  "istable": 0, 
  "max_attachments": 0, 
  "menu_index": 0, 
- "modified": "2016-07-27 03:52:28.509757", 
+ "modified": "2016-08-26 02:28:48.877990", 
  "modified_by": "Administrator", 
  "module": "Schools", 
  "name": "Fees", 
diff --git a/erpnext/schools/doctype/grade_interval/__init__.py b/erpnext/schools/doctype/grade_interval/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/schools/doctype/grade_interval/__init__.py
diff --git a/erpnext/schools/doctype/grade_interval/grade_interval.json b/erpnext/schools/doctype/grade_interval/grade_interval.json
new file mode 100644
index 0000000..79ef9f4
--- /dev/null
+++ b/erpnext/schools/doctype/grade_interval/grade_interval.json
@@ -0,0 +1,137 @@
+{
+ "allow_copy": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "beta": 0, 
+ "creation": "2016-08-26 03:11:09.591049", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "fields": [
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "grade_code", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 1, 
+   "label": "Grade Code", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "from_score", 
+   "fieldtype": "Float", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 1, 
+   "label": "From Score", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "1", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "to_score", 
+   "fieldtype": "Float", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 1, 
+   "label": "To Score", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "1", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "grade_description", 
+   "fieldtype": "Small Text", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 1, 
+   "label": "Grade Description", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }
+ ], 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "in_dialog": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 1, 
+ "max_attachments": 0, 
+ "modified": "2016-08-27 15:45:04.657328", 
+ "modified_by": "Administrator", 
+ "module": "Schools", 
+ "name": "Grade Interval", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [], 
+ "quick_entry": 1, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/schools/doctype/grade_interval/grade_interval.py b/erpnext/schools/doctype/grade_interval/grade_interval.py
new file mode 100644
index 0000000..c8ded13
--- /dev/null
+++ b/erpnext/schools/doctype/grade_interval/grade_interval.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class GradeInterval(Document):
+    def validate(self):
+        pass
\ No newline at end of file
diff --git a/erpnext/schools/doctype/grading_structure/__init__.py b/erpnext/schools/doctype/grading_structure/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/schools/doctype/grading_structure/__init__.py
diff --git a/erpnext/schools/doctype/grading_structure/grading_structure.js b/erpnext/schools/doctype/grading_structure/grading_structure.js
new file mode 100644
index 0000000..36f4504
--- /dev/null
+++ b/erpnext/schools/doctype/grading_structure/grading_structure.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Grading Structure', {
+	refresh: function(frm) {
+
+	}
+});
diff --git a/erpnext/schools/doctype/grading_structure/grading_structure.json b/erpnext/schools/doctype/grading_structure/grading_structure.json
new file mode 100644
index 0000000..cda6bd4
--- /dev/null
+++ b/erpnext/schools/doctype/grading_structure/grading_structure.json
@@ -0,0 +1,185 @@
+{
+ "allow_copy": 0, 
+ "allow_import": 0, 
+ "allow_rename": 1, 
+ "autoname": "field:grading_system_name", 
+ "beta": 0, 
+ "creation": "2016-08-26 03:06:53.922972", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "fields": [
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "grading_system_name", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 1, 
+   "label": "Grading System Name", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "description", 
+   "fieldtype": "Text", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 1, 
+   "label": "Description", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "column_break_3", 
+   "fieldtype": "Column Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 0, 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "grading_intervals_section", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 0, 
+   "label": "Grading Intervals", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "fieldname": "grade_intervals", 
+   "fieldtype": "Table", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 0, 
+   "label": "Grade Intervals", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Grade Interval", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }
+ ], 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "in_dialog": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 0, 
+ "max_attachments": 0, 
+ "modified": "2016-08-27 14:20:50.709823", 
+ "modified_by": "Administrator", 
+ "module": "Schools", 
+ "name": "Grading Structure", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [
+  {
+   "amend": 0, 
+   "apply_user_permissions": 0, 
+   "cancel": 0, 
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 1, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "Academics User", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }
+ ], 
+ "quick_entry": 1, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "title_field": "grading_system_name", 
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/schools/doctype/grading_structure/grading_structure.py b/erpnext/schools/doctype/grading_structure/grading_structure.py
new file mode 100644
index 0000000..1b5d6a8
--- /dev/null
+++ b/erpnext/schools/doctype/grading_structure/grading_structure.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+from frappe import _
+from frappe.utils import cstr
+
+class GradingStructure(Document):
+    def validate(self):
+        grade_intervals = self.get("grade_intervals")
+        check_overlap(grade_intervals, self)
+
+#Check if any of the grade intervals for this grading structure overlap
+def check_overlap(grade_intervals, parent_doc):
+    for interval1 in grade_intervals:
+        for interval2 in grade_intervals:
+            if interval1.name == interval2.name:
+                pass
+            else:
+                if (interval1.from_score <= interval2.from_score and interval1.to_score >= interval2.from_score) or (interval1.from_score <= interval2.to_score and interval1.to_score >= interval2.to_score):
+                    frappe.throw(_("""The intervals for Grade Code {0} overlaps with the grade intervals for other grades. 
+                    Please check intervals {0} and {1} and try again""".format(interval1.grade_code, interval2.grade_code))) 
\ No newline at end of file
diff --git a/erpnext/schools/doctype/grading_structure/test_grading_structure.py b/erpnext/schools/doctype/grading_structure/test_grading_structure.py
new file mode 100644
index 0000000..0e36080
--- /dev/null
+++ b/erpnext/schools/doctype/grading_structure/test_grading_structure.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+
+# test_records = frappe.get_test_records('Grading Structure')
+
+class TestGradingStructure(unittest.TestCase):
+	pass
diff --git a/erpnext/schools/doctype/program/program.json b/erpnext/schools/doctype/program/program.json
index acd5a8e..ca6e1df 100644
--- a/erpnext/schools/doctype/program/program.json
+++ b/erpnext/schools/doctype/program/program.json
@@ -250,7 +250,7 @@
  "istable": 0, 
  "max_attachments": 0, 
  "menu_index": 0, 
- "modified": "2016-07-25 01:33:56.912243", 
+ "modified": "2016-08-27 03:21:35.806511", 
  "modified_by": "Administrator", 
  "module": "Schools", 
  "name": "Program", 
diff --git a/erpnext/schools/doctype/program_enrollment/program_enrollment.js b/erpnext/schools/doctype/program_enrollment/program_enrollment.js
index 038afd9..72fc6f2 100644
--- a/erpnext/schools/doctype/program_enrollment/program_enrollment.js
+++ b/erpnext/schools/doctype/program_enrollment/program_enrollment.js
@@ -18,5 +18,23 @@
 				}
 			});
 		}
+	},
+	
+	onload: function(frm, cdt, cdn){
+		cur_frm.set_query("academic_term", "fees", function(){
+			return{
+				"filters":{
+					"academic_year": (frm.doc.academic_year)
+				}
+			};
+		});
+				
+		cur_frm.fields_dict['fees'].grid.get_field('fee_structure').get_query = function(doc, cdt, cdn) {
+			var d = locals[cdt][cdn];
+			return {
+				filters: {'academic_term': d.academic_term}
+			}
+		};
+		
 	}
 });
diff --git a/erpnext/schools/doctype/student/student.json b/erpnext/schools/doctype/student/student.json
index 22b8c4e..454aeb2 100644
--- a/erpnext/schools/doctype/student/student.json
+++ b/erpnext/schools/doctype/student/student.json
@@ -165,7 +165,7 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
-   "default": "Today", 
+   "default": "", 
    "fieldname": "joining_date", 
    "fieldtype": "Date", 
    "hidden": 0, 
@@ -180,7 +180,7 @@
    "precision": "", 
    "print_hide": 0, 
    "print_hide_if_no_value": 0, 
-   "read_only": 1, 
+   "read_only": 0, 
    "report_hide": 0, 
    "reqd": 0, 
    "search_index": 0, 
@@ -371,7 +371,7 @@
    "bold": 0, 
    "collapsible": 0, 
    "fieldname": "nationality", 
-   "fieldtype": "Data", 
+   "fieldtype": "Link", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
@@ -380,6 +380,7 @@
    "label": "Nationality", 
    "length": 0, 
    "no_copy": 0, 
+   "options": "Country", 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
@@ -456,7 +457,7 @@
  "istable": 0, 
  "max_attachments": 0, 
  "menu_index": 0, 
- "modified": "2016-07-25 07:22:57.581638", 
+ "modified": "2016-08-21 05:41:34.091353", 
  "modified_by": "Administrator", 
  "module": "Schools", 
  "name": "Student", 
diff --git a/erpnext/schools/doctype/student_applicant/student_applicant.json b/erpnext/schools/doctype/student_applicant/student_applicant.json
index b9505a5..8dbd22a 100644
--- a/erpnext/schools/doctype/student_applicant/student_applicant.json
+++ b/erpnext/schools/doctype/student_applicant/student_applicant.json
@@ -525,7 +525,7 @@
    "bold": 0, 
    "collapsible": 0, 
    "fieldname": "nationality", 
-   "fieldtype": "Data", 
+   "fieldtype": "Link", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
@@ -534,6 +534,7 @@
    "label": "Nationality", 
    "length": 0, 
    "no_copy": 0, 
+   "options": "Country", 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
@@ -633,7 +634,7 @@
  "istable": 0, 
  "max_attachments": 0, 
  "menu_index": 0, 
- "modified": "2016-07-25 01:24:27.384647", 
+ "modified": "2016-08-26 01:01:45.669665", 
  "modified_by": "Administrator", 
  "module": "Schools", 
  "name": "Student Applicant", 
diff --git a/erpnext/schools/doctype/student_batch/student_batch.js b/erpnext/schools/doctype/student_batch/student_batch.js
index 73d4faa..931e41b 100644
--- a/erpnext/schools/doctype/student_batch/student_batch.js
+++ b/erpnext/schools/doctype/student_batch/student_batch.js
@@ -4,7 +4,18 @@
 frappe.ui.form.on('Student Batch', {
 	refresh: function(frm) {
 
+	},
+	
+	onload: function(frm){
+		cur_frm.set_query("academic_term",function(){
+			return{
+				"filters":{
+					"academic_year": (frm.doc.academic_year)
+				}
+			};
+		});
 	}
+	
 });
 
 cur_frm.add_fetch("student", "title", "student_name");
diff --git a/erpnext/schools/doctype/student_batch/student_batch.json b/erpnext/schools/doctype/student_batch/student_batch.json
index a806ae3..fa7e6b5 100644
--- a/erpnext/schools/doctype/student_batch/student_batch.json
+++ b/erpnext/schools/doctype/student_batch/student_batch.json
@@ -199,7 +199,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2016-07-22 09:19:51.141234", 
+ "modified": "2016-08-24 05:32:00.585277", 
  "modified_by": "Administrator", 
  "module": "Schools", 
  "name": "Student Batch", 
diff --git a/erpnext/schools/doctype/student_batch/student_batch.py b/erpnext/schools/doctype/student_batch/student_batch.py
index 107ef93..ec2dc79 100644
--- a/erpnext/schools/doctype/student_batch/student_batch.py
+++ b/erpnext/schools/doctype/student_batch/student_batch.py
@@ -8,12 +8,12 @@
 import frappe
 
 class StudentBatch(Document):
-	def autoname(self):
-		prog_abb = frappe.db.get_value("Program", self.program, "program_abbreviation")
-		if not prog_abb:
-			prog_abb = self.program
-		self.name = prog_abb + "-"+ self.student_batch_name + "-" + self.academic_year
-	
-	def validate(self):
-		validate_duplicate_student(self.students)
-		
\ No newline at end of file
+    def autoname(self):
+        prog_abb = frappe.db.get_value("Program", self.program, "program_abbreviation")
+        if not prog_abb:
+            prog_abb = self.program
+        self.name = prog_abb + "-"+ self.student_batch_name + "-" + self.academic_year
+        
+    def validate(self):
+        validate_duplicate_student(self.students)
+        
\ No newline at end of file
diff --git a/erpnext/schools/doctype/student_group/student_group.js b/erpnext/schools/doctype/student_group/student_group.js
index eed3342..784f557 100644
--- a/erpnext/schools/doctype/student_group/student_group.js
+++ b/erpnext/schools/doctype/student_group/student_group.js
@@ -16,4 +16,19 @@
 			frappe.set_route("List", "Assessment");
 		});
 	}
-});
\ No newline at end of file
+});
+
+frappe.ui.form.on("Student Group", "onload", function(frm){
+	cur_frm.set_query("academic_term",function(){
+		return{
+			"filters":{
+				"academic_year": (frm.doc.academic_year)
+			}
+		};
+	});
+});
+
+//If Student Batch is entered, deduce program, academic_year and academic term from it
+cur_frm.add_fetch("student_batch", "program", "program");
+cur_frm.add_fetch("student_batch", "academic_term", "academic_term");
+cur_frm.add_fetch("student_batch", "academic_year", "academic_year");
diff --git a/erpnext/schools/doctype/student_group/student_group.json b/erpnext/schools/doctype/student_group/student_group.json
index e4b4ea3..a0584e3 100644
--- a/erpnext/schools/doctype/student_group/student_group.json
+++ b/erpnext/schools/doctype/student_group/student_group.json
@@ -41,17 +41,17 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
-   "fieldname": "academic_term", 
+   "fieldname": "academic_year", 
    "fieldtype": "Link", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
    "in_filter": 0, 
    "in_list_view": 1, 
-   "label": "Academic Term", 
+   "label": "Academic Year", 
    "length": 0, 
    "no_copy": 0, 
-   "options": "Academic Term", 
+   "options": "Academic Year", 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
@@ -67,17 +67,17 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
-   "fieldname": "academic_year", 
+   "fieldname": "academic_term", 
    "fieldtype": "Link", 
    "hidden": 0, 
    "ignore_user_permissions": 0, 
    "ignore_xss_filter": 0, 
    "in_filter": 0, 
    "in_list_view": 1, 
-   "label": "Academic Year", 
+   "label": "Academic Term", 
    "length": 0, 
    "no_copy": 0, 
-   "options": "Academic Year", 
+   "options": "Academic Term", 
    "permlevel": 0, 
    "precision": "", 
    "print_hide": 0, 
@@ -280,7 +280,7 @@
  "istable": 0, 
  "max_attachments": 0, 
  "menu_index": 0, 
- "modified": "2016-07-25 06:23:43.903111", 
+ "modified": "2016-08-24 05:21:05.058875", 
  "modified_by": "Administrator", 
  "module": "Schools", 
  "name": "Student Group", 
diff --git a/erpnext/schools/doctype/student_group/test_records.json b/erpnext/schools/doctype/student_group/test_records.json
index a14f670..27cd181 100644
--- a/erpnext/schools/doctype/student_group/test_records.json
+++ b/erpnext/schools/doctype/student_group/test_records.json
@@ -3,12 +3,12 @@
 		"program": "_Test Program",
 		"course": "_Test Course",
 		"academic_year": "2014-2015",
-		"academic_term": "_Test Academic Term"
+		"academic_term": "2014-2015 (_Test Academic Term)"
 	},
 	{
 		"program": "_Test Program",
 		"course": "_Test Course 2",
 		"academic_year": "2014-2015",
-		"academic_term": "_Test Academic Term"
+		"academic_term": "2014-2015 (_Test Academic Term)"
 	}
 ]
\ No newline at end of file
diff --git a/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.js b/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.js
index 056574c..9c796bb 100644
--- a/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.js
+++ b/erpnext/schools/doctype/student_group_creation_tool/student_group_creation_tool.js
@@ -20,4 +20,14 @@
 			}
 		}
 	})
+});
+
+frappe.ui.form.on("Student Group Creation Tool", "onload", function(frm){
+	cur_frm.set_query("academic_term",function(){
+		return{
+			"filters":{
+				"academic_year": (frm.doc.academic_year)
+			}
+		};
+	});
 });
\ No newline at end of file
diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py
index 191f169..945dfb1 100644
--- a/erpnext/setup/setup_wizard/setup_wizard.py
+++ b/erpnext/setup/setup_wizard/setup_wizard.py
@@ -15,538 +15,541 @@
 from erpnext.setup.setup_wizard.domainify import setup_domain
 
 def setup_complete(args=None):
-	if frappe.db.sql("select name from tabCompany"):
-		frappe.throw(_("Setup Already Complete!!"))
+    if frappe.db.sql("select name from tabCompany"):
+        frappe.throw(_("Setup Already Complete!!"))
 
-	install_fixtures.install(args.get("country"))
+    install_fixtures.install(args.get("country"))
 
-	create_price_lists(args)
-	create_fiscal_year_and_company(args)
-	create_users(args)
-	set_defaults(args)
-	create_territories()
-	create_feed_and_todo()
-	create_email_digest()
-	create_letter_head(args)
-	create_taxes(args)
-	create_items(args)
-	create_customers(args)
-	create_suppliers(args)
+    create_price_lists(args)
+    create_fiscal_year_and_company(args)
+    create_users(args)
+    set_defaults(args)
+    create_territories()
+    create_feed_and_todo()
+    create_email_digest()
+    create_letter_head(args)
+    create_taxes(args)
+    create_items(args)
+    create_customers(args)
+    create_suppliers(args)
 
-	if args.domain.lower() == 'education':
-		create_academic_term()
-		create_academic_year()
-		create_program(args)
-		create_course(args)
-		create_instructor(args)
-		create_room(args)
+    if args.domain.lower() == 'education':
+        create_academic_year()
+        create_academic_term()
+        create_program(args)
+        create_course(args)
+        create_instructor(args)
+        create_room(args)
 
-	if args.get('setup_website'):
-		website_maker(args)
+    if args.get('setup_website'):
+        website_maker(args)
 
-	create_logo(args)
+    create_logo(args)
 
-	frappe.local.message_log = []
-	setup_domain(args.get('domain'))
+    frappe.local.message_log = []
+    setup_domain(args.get('domain'))
 
-	frappe.db.commit()
-	login_as_first_user(args)
+    frappe.db.commit()
+    login_as_first_user(args)
 
-	frappe.db.commit()
-	frappe.clear_cache()
+    frappe.db.commit()
+    frappe.clear_cache()
 
-	if args.get("add_sample_data"):
-		try:
-			make_sample_data()
-			frappe.clear_cache()
-		except:
-			# clear message
-			if frappe.message_log:
-				frappe.message_log.pop()
+    if args.get("add_sample_data"):
+        try:
+            make_sample_data()
+            frappe.clear_cache()
+        except:
+            # clear message
+            if frappe.message_log:
+                frappe.message_log.pop()
 
-			pass
+            pass
 
 def create_fiscal_year_and_company(args):
-	if (args.get('fy_start_date')):
-		curr_fiscal_year = get_fy_details(args.get('fy_start_date'), args.get('fy_end_date'))
-		frappe.get_doc({
-		"doctype":"Fiscal Year",
-		'year': curr_fiscal_year,
-		'year_start_date': args.get('fy_start_date'),
-		'year_end_date': args.get('fy_end_date'),
-		}).insert()
-		args["curr_fiscal_year"] = curr_fiscal_year
+    if (args.get('fy_start_date')):
+        curr_fiscal_year = get_fy_details(args.get('fy_start_date'), args.get('fy_end_date'))
+        frappe.get_doc({
+        "doctype":"Fiscal Year",
+        'year': curr_fiscal_year,
+        'year_start_date': args.get('fy_start_date'),
+        'year_end_date': args.get('fy_end_date'),
+        }).insert()
+        args["curr_fiscal_year"] = curr_fiscal_year
 
-	# Company
-	if (args.get('company_name')):
-		frappe.get_doc({
-			"doctype":"Company",
-			'company_name':args.get('company_name').strip(),
-			'abbr':args.get('company_abbr'),
-			'default_currency':args.get('currency'),
-			'country': args.get('country'),
-			'chart_of_accounts': args.get(('chart_of_accounts')),
-			'domain': args.get('domain')
-		}).insert()
+    # Company
+    if (args.get('company_name')):
+        frappe.get_doc({
+            "doctype":"Company",
+            'company_name':args.get('company_name').strip(),
+            'abbr':args.get('company_abbr'),
+            'default_currency':args.get('currency'),
+            'country': args.get('country'),
+            'chart_of_accounts': args.get(('chart_of_accounts')),
+            'domain': args.get('domain')
+        }).insert()
 
-		#Enable shopping cart
-		enable_shopping_cart(args)
+        #Enable shopping cart
+        enable_shopping_cart(args)
 
-		# Bank Account
-		create_bank_account(args)
+        # Bank Account
+        create_bank_account(args)
 
 def enable_shopping_cart(args):
-	frappe.get_doc({
-		"doctype": "Shopping Cart Settings",
-		"enabled": 1,
-		'company': args.get('company_name').strip(),
-		'price_list': frappe.db.get_value("Price List", {"selling": 1}),
-		'default_customer_group': _("Individual"),
-		'quotation_series': "QTN-",
-	}).insert()
+    frappe.get_doc({
+        "doctype": "Shopping Cart Settings",
+        "enabled": 1,
+        'company': args.get('company_name').strip(),
+        'price_list': frappe.db.get_value("Price List", {"selling": 1}),
+        'default_customer_group': _("Individual"),
+        'quotation_series': "QTN-",
+    }).insert()
 
 def create_bank_account(args):
-	if args.get("bank_account"):
-		company_name = args.get('company_name').strip()
-		bank_account_group =  frappe.db.get_value("Account",
-			{"account_type": "Bank", "is_group": 1, "root_type": "Asset",
-				"company": company_name})
-		if bank_account_group:
-			bank_account = frappe.get_doc({
-				"doctype": "Account",
-				'account_name': args.get("bank_account"),
-				'parent_account': bank_account_group,
-				'is_group':0,
-				'company': company_name,
-				"account_type": "Bank",
-			})
-			try:
-				return bank_account.insert()
-			except RootNotEditable:
-				frappe.throw(_("Bank account cannot be named as {0}").format(args.get("bank_account")))
-			except frappe.DuplicateEntryError:
-				# bank account same as a CoA entry
-				pass
+    if args.get("bank_account"):
+        company_name = args.get('company_name').strip()
+        bank_account_group =  frappe.db.get_value("Account",
+            {"account_type": "Bank", "is_group": 1, "root_type": "Asset",
+                "company": company_name})
+        if bank_account_group:
+            bank_account = frappe.get_doc({
+                "doctype": "Account",
+                'account_name': args.get("bank_account"),
+                'parent_account': bank_account_group,
+                'is_group':0,
+                'company': company_name,
+                "account_type": "Bank",
+            })
+            try:
+                return bank_account.insert()
+            except RootNotEditable:
+                frappe.throw(_("Bank account cannot be named as {0}").format(args.get("bank_account")))
+            except frappe.DuplicateEntryError:
+                # bank account same as a CoA entry
+                pass
 
 def create_price_lists(args):
-	for pl_type, pl_name in (("Selling", _("Standard Selling")), ("Buying", _("Standard Buying"))):
-		frappe.get_doc({
-			"doctype": "Price List",
-			"price_list_name": pl_name,
-			"enabled": 1,
-			"buying": 1 if pl_type == "Buying" else 0,
-			"selling": 1 if pl_type == "Selling" else 0,
-			"currency": args["currency"]
-		}).insert()
+    for pl_type, pl_name in (("Selling", _("Standard Selling")), ("Buying", _("Standard Buying"))):
+        frappe.get_doc({
+            "doctype": "Price List",
+            "price_list_name": pl_name,
+            "enabled": 1,
+            "buying": 1 if pl_type == "Buying" else 0,
+            "selling": 1 if pl_type == "Selling" else 0,
+            "currency": args["currency"]
+        }).insert()
 
 def set_defaults(args):
-	# enable default currency
-	frappe.db.set_value("Currency", args.get("currency"), "enabled", 1)
+    # enable default currency
+    frappe.db.set_value("Currency", args.get("currency"), "enabled", 1)
 
-	global_defaults = frappe.get_doc("Global Defaults", "Global Defaults")
-	global_defaults.update({
-		'current_fiscal_year': args.curr_fiscal_year,
-		'default_currency': args.get('currency'),
-		'default_company':args.get('company_name').strip(),
-		"country": args.get("country"),
-	})
+    global_defaults = frappe.get_doc("Global Defaults", "Global Defaults")
+    global_defaults.update({
+        'current_fiscal_year': args.curr_fiscal_year,
+        'default_currency': args.get('currency'),
+        'default_company':args.get('company_name').strip(),
+        "country": args.get("country"),
+    })
 
-	global_defaults.save()
+    global_defaults.save()
 
-	frappe.db.set_value("System Settings", None, "email_footer_address", args.get("company"))
+    frappe.db.set_value("System Settings", None, "email_footer_address", args.get("company"))
 
-	accounts_settings = frappe.get_doc("Accounts Settings")
-	accounts_settings.auto_accounting_for_stock = 1
-	accounts_settings.save()
+    accounts_settings = frappe.get_doc("Accounts Settings")
+    accounts_settings.auto_accounting_for_stock = 1
+    accounts_settings.save()
 
-	stock_settings = frappe.get_doc("Stock Settings")
-	stock_settings.item_naming_by = "Item Code"
-	stock_settings.valuation_method = "FIFO"
-	stock_settings.default_warehouse = frappe.db.get_value('Warehouse', {'warehouse_name': _('Stores')})
-	stock_settings.stock_uom = _("Nos")
-	stock_settings.auto_indent = 1
-	stock_settings.auto_insert_price_list_rate_if_missing = 1
-	stock_settings.automatically_set_serial_nos_based_on_fifo = 1
-	stock_settings.save()
+    stock_settings = frappe.get_doc("Stock Settings")
+    stock_settings.item_naming_by = "Item Code"
+    stock_settings.valuation_method = "FIFO"
+    stock_settings.default_warehouse = frappe.db.get_value('Warehouse', {'warehouse_name': _('Stores')})
+    stock_settings.stock_uom = _("Nos")
+    stock_settings.auto_indent = 1
+    stock_settings.auto_insert_price_list_rate_if_missing = 1
+    stock_settings.automatically_set_serial_nos_based_on_fifo = 1
+    stock_settings.save()
 
-	selling_settings = frappe.get_doc("Selling Settings")
-	selling_settings.cust_master_name = "Customer Name"
-	selling_settings.so_required = "No"
-	selling_settings.dn_required = "No"
-	selling_settings.save()
+    selling_settings = frappe.get_doc("Selling Settings")
+    selling_settings.cust_master_name = "Customer Name"
+    selling_settings.so_required = "No"
+    selling_settings.dn_required = "No"
+    selling_settings.save()
 
-	buying_settings = frappe.get_doc("Buying Settings")
-	buying_settings.supp_master_name = "Supplier Name"
-	buying_settings.po_required = "No"
-	buying_settings.pr_required = "No"
-	buying_settings.maintain_same_rate = 1
-	buying_settings.save()
+    buying_settings = frappe.get_doc("Buying Settings")
+    buying_settings.supp_master_name = "Supplier Name"
+    buying_settings.po_required = "No"
+    buying_settings.pr_required = "No"
+    buying_settings.maintain_same_rate = 1
+    buying_settings.save()
 
-	notification_control = frappe.get_doc("Notification Control")
-	notification_control.quotation = 1
-	notification_control.sales_invoice = 1
-	notification_control.purchase_order = 1
-	notification_control.save()
+    notification_control = frappe.get_doc("Notification Control")
+    notification_control.quotation = 1
+    notification_control.sales_invoice = 1
+    notification_control.purchase_order = 1
+    notification_control.save()
 
-	hr_settings = frappe.get_doc("HR Settings")
-	hr_settings.emp_created_by = "Naming Series"
-	hr_settings.save()
+    hr_settings = frappe.get_doc("HR Settings")
+    hr_settings.emp_created_by = "Naming Series"
+    hr_settings.save()
 
 def create_feed_and_todo():
-	"""update Activity feed and create todo for creation of item, customer, vendor"""
-	add_info_comment(**{
-		"subject": _("ERPNext Setup Complete!")
-	})
+    """update Activity feed and create todo for creation of item, customer, vendor"""
+    add_info_comment(**{
+        "subject": _("ERPNext Setup Complete!")
+    })
 
 def create_email_digest():
-	from frappe.utils.user import get_system_managers
-	system_managers = get_system_managers(only_name=True)
-	if not system_managers:
-		return
+    from frappe.utils.user import get_system_managers
+    system_managers = get_system_managers(only_name=True)
+    if not system_managers:
+        return
 
-	companies = frappe.db.sql_list("select name FROM `tabCompany`")
-	for company in companies:
-		if not frappe.db.exists("Email Digest", "Default Weekly Digest - " + company):
-			edigest = frappe.get_doc({
-				"doctype": "Email Digest",
-				"name": "Default Weekly Digest - " + company,
-				"company": company,
-				"frequency": "Weekly",
-				"recipient_list": "\n".join(system_managers)
-			})
+    companies = frappe.db.sql_list("select name FROM `tabCompany`")
+    for company in companies:
+        if not frappe.db.exists("Email Digest", "Default Weekly Digest - " + company):
+            edigest = frappe.get_doc({
+                "doctype": "Email Digest",
+                "name": "Default Weekly Digest - " + company,
+                "company": company,
+                "frequency": "Weekly",
+                "recipient_list": "\n".join(system_managers)
+            })
 
-			for df in edigest.meta.get("fields", {"fieldtype": "Check"}):
-				if df.fieldname != "scheduler_errors":
-					edigest.set(df.fieldname, 1)
+            for df in edigest.meta.get("fields", {"fieldtype": "Check"}):
+                if df.fieldname != "scheduler_errors":
+                    edigest.set(df.fieldname, 1)
 
-			edigest.insert()
+            edigest.insert()
 
-	# scheduler errors digest
-	if companies:
-		edigest = frappe.new_doc("Email Digest")
-		edigest.update({
-			"name": "Scheduler Errors",
-			"company": companies[0],
-			"frequency": "Daily",
-			"recipient_list": "\n".join(system_managers),
-			"scheduler_errors": 1,
-			"enabled": 1
-		})
-		edigest.insert()
+    # scheduler errors digest
+    if companies:
+        edigest = frappe.new_doc("Email Digest")
+        edigest.update({
+            "name": "Scheduler Errors",
+            "company": companies[0],
+            "frequency": "Daily",
+            "recipient_list": "\n".join(system_managers),
+            "scheduler_errors": 1,
+            "enabled": 1
+        })
+        edigest.insert()
 
 def get_fy_details(fy_start_date, fy_end_date):
-	start_year = getdate(fy_start_date).year
-	if start_year == getdate(fy_end_date).year:
-		fy = cstr(start_year)
-	else:
-		fy = cstr(start_year) + '-' + cstr(start_year + 1)
-	return fy
+    start_year = getdate(fy_start_date).year
+    if start_year == getdate(fy_end_date).year:
+        fy = cstr(start_year)
+    else:
+        fy = cstr(start_year) + '-' + cstr(start_year + 1)
+    return fy
 
 def create_taxes(args):
 
-	for i in xrange(1,6):
-		if args.get("tax_" + str(i)):
-			# replace % in case someone also enters the % symbol
-			tax_rate = cstr(args.get("tax_rate_" + str(i)) or "").replace("%", "")
+    for i in xrange(1,6):
+        if args.get("tax_" + str(i)):
+            # replace % in case someone also enters the % symbol
+            tax_rate = cstr(args.get("tax_rate_" + str(i)) or "").replace("%", "")
 
-			try:
-				tax_group = frappe.db.get_value("Account", {"company": args.get("company_name"),
-					"is_group": 1, "account_type": "Tax", "root_type": "Liability"})
-				if tax_group:
-					account = make_tax_head(args, i, tax_group, tax_rate)
-					make_sales_and_purchase_tax_templates(account)
+            try:
+                tax_group = frappe.db.get_value("Account", {"company": args.get("company_name"),
+                    "is_group": 1, "account_type": "Tax", "root_type": "Liability"})
+                if tax_group:
+                    account = make_tax_head(args, i, tax_group, tax_rate)
+                    make_sales_and_purchase_tax_templates(account)
 
-			except frappe.NameError, e:
-				if e.args[2][0]==1062:
-					pass
-				else:
-					raise
-			except RootNotEditable, e:
-				pass
+            except frappe.NameError, e:
+                if e.args[2][0]==1062:
+                    pass
+                else:
+                    raise
+            except RootNotEditable, e:
+                pass
 
 def make_tax_head(args, i, tax_group, tax_rate):
-	return frappe.get_doc({
-		"doctype":"Account",
-		"company": args.get("company_name").strip(),
-		"parent_account": tax_group,
-		"account_name": args.get("tax_" + str(i)),
-		"is_group": 0,
-		"report_type": "Balance Sheet",
-		"account_type": "Tax",
-		"tax_rate": flt(tax_rate) if tax_rate else None
-	}).insert(ignore_permissions=True)
+    return frappe.get_doc({
+        "doctype":"Account",
+        "company": args.get("company_name").strip(),
+        "parent_account": tax_group,
+        "account_name": args.get("tax_" + str(i)),
+        "is_group": 0,
+        "report_type": "Balance Sheet",
+        "account_type": "Tax",
+        "tax_rate": flt(tax_rate) if tax_rate else None
+    }).insert(ignore_permissions=True)
 
 def make_sales_and_purchase_tax_templates(account):
-	doc = {
-		"doctype": "Sales Taxes and Charges Template",
-		"title": account.name,
-		"taxes": [{
-		    "category": "Valuation and Total",
-		    "charge_type": "On Net Total",
-			"account_head": account.name,
-			"description": "{0} @ {1}".format(account.account_name, account.tax_rate),
-			"rate": account.tax_rate
-		}]
-	}
+    doc = {
+        "doctype": "Sales Taxes and Charges Template",
+        "title": account.name,
+        "taxes": [{
+            "category": "Valuation and Total",
+            "charge_type": "On Net Total",
+            "account_head": account.name,
+            "description": "{0} @ {1}".format(account.account_name, account.tax_rate),
+            "rate": account.tax_rate
+        }]
+    }
 
-	# Sales
-	frappe.get_doc(copy.deepcopy(doc)).insert()
+    # Sales
+    frappe.get_doc(copy.deepcopy(doc)).insert()
 
-	# Purchase
-	doc["doctype"] = "Purchase Taxes and Charges Template"
-	frappe.get_doc(copy.deepcopy(doc)).insert()
+    # Purchase
+    doc["doctype"] = "Purchase Taxes and Charges Template"
+    frappe.get_doc(copy.deepcopy(doc)).insert()
 
 def create_items(args):
-	for i in xrange(1,6):
-		item = args.get("item_" + str(i))
-		if item:
-			item_group = args.get("item_group_" + str(i))
-			is_sales_item = args.get("is_sales_item_" + str(i))
-			is_purchase_item = args.get("is_purchase_item_" + str(i))
-			is_stock_item = item_group!=_("Services")
-			default_warehouse = ""
-			if is_stock_item:
-				default_warehouse = frappe.db.get_value("Warehouse", filters={
-					"warehouse_name": _("Finished Goods") if is_sales_item else _("Stores"),
-					"company": args.get("company_name").strip()
-				})
+    for i in xrange(1,6):
+        item = args.get("item_" + str(i))
+        if item:
+            item_group = args.get("item_group_" + str(i))
+            is_sales_item = args.get("is_sales_item_" + str(i))
+            is_purchase_item = args.get("is_purchase_item_" + str(i))
+            is_stock_item = item_group!=_("Services")
+            default_warehouse = ""
+            if is_stock_item:
+                default_warehouse = frappe.db.get_value("Warehouse", filters={
+                    "warehouse_name": _("Finished Goods") if is_sales_item else _("Stores"),
+                    "company": args.get("company_name").strip()
+                })
 
-			try:
-				frappe.get_doc({
-					"doctype":"Item",
-					"item_code": item,
-					"item_name": item,
-					"description": item,
-					"show_in_website": 1,
-					"is_sales_item": is_sales_item,
-					"is_purchase_item": is_purchase_item,
-					"is_stock_item": is_stock_item and 1 or 0,
-					"item_group": item_group,
-					"stock_uom": args.get("item_uom_" + str(i)),
-					"default_warehouse": default_warehouse
-				}).insert()
+            try:
+                frappe.get_doc({
+                    "doctype":"Item",
+                    "item_code": item,
+                    "item_name": item,
+                    "description": item,
+                    "show_in_website": 1,
+                    "is_sales_item": is_sales_item,
+                    "is_purchase_item": is_purchase_item,
+                    "is_stock_item": is_stock_item and 1 or 0,
+                    "item_group": item_group,
+                    "stock_uom": args.get("item_uom_" + str(i)),
+                    "default_warehouse": default_warehouse
+                }).insert()
 
-				if args.get("item_img_" + str(i)):
-					item_image = args.get("item_img_" + str(i)).split(",")
-					if len(item_image)==3:
-						filename, filetype, content = item_image
-						fileurl = save_file(filename, content, "Item", item, decode=True).file_url
-						frappe.db.set_value("Item", item, "image", fileurl)
+                if args.get("item_img_" + str(i)):
+                    item_image = args.get("item_img_" + str(i)).split(",")
+                    if len(item_image)==3:
+                        filename, filetype, content = item_image
+                        fileurl = save_file(filename, content, "Item", item, decode=True).file_url
+                        frappe.db.set_value("Item", item, "image", fileurl)
 
-				if args.get("item_price_" + str(i)):
-					item_price = flt(args.get("item_price_" + str(i)))
+                if args.get("item_price_" + str(i)):
+                    item_price = flt(args.get("item_price_" + str(i)))
 
-					if is_sales_item:
-						price_list_name = frappe.db.get_value("Price List", {"selling": 1})
-						make_item_price(item, price_list_name, item_price)
+                    if is_sales_item:
+                        price_list_name = frappe.db.get_value("Price List", {"selling": 1})
+                        make_item_price(item, price_list_name, item_price)
 
-					if is_purchase_item:
-						price_list_name = frappe.db.get_value("Price List", {"buying": 1})
-						make_item_price(item, price_list_name, item_price)
+                    if is_purchase_item:
+                        price_list_name = frappe.db.get_value("Price List", {"buying": 1})
+                        make_item_price(item, price_list_name, item_price)
 
-			except frappe.NameError:
-				pass
+            except frappe.NameError:
+                pass
 
 def make_item_price(item, price_list_name, item_price):
-	frappe.get_doc({
-		"doctype": "Item Price",
-		"price_list": price_list_name,
-		"item_code": item,
-		"price_list_rate": item_price
-	}).insert()
+    frappe.get_doc({
+        "doctype": "Item Price",
+        "price_list": price_list_name,
+        "item_code": item,
+        "price_list_rate": item_price
+    }).insert()
 
 
 def create_customers(args):
-	for i in xrange(1,6):
-		customer = args.get("customer_" + str(i))
-		if customer:
-			try:
-				doc = frappe.get_doc({
-					"doctype":"Customer",
-					"customer_name": customer,
-					"customer_type": "Company",
-					"customer_group": _("Commercial"),
-					"territory": args.get("country"),
-					"company": args.get("company_name").strip()
-				}).insert()
+    for i in xrange(1,6):
+        customer = args.get("customer_" + str(i))
+        if customer:
+            try:
+                doc = frappe.get_doc({
+                    "doctype":"Customer",
+                    "customer_name": customer,
+                    "customer_type": "Company",
+                    "customer_group": _("Commercial"),
+                    "territory": args.get("country"),
+                    "company": args.get("company_name").strip()
+                }).insert()
 
-				if args.get("customer_contact_" + str(i)):
-					create_contact(args.get("customer_contact_" + str(i)),
-						"customer", doc.name)
-			except frappe.NameError:
-				pass
+                if args.get("customer_contact_" + str(i)):
+                    create_contact(args.get("customer_contact_" + str(i)),
+                        "customer", doc.name)
+            except frappe.NameError:
+                pass
 
 def create_suppliers(args):
-	for i in xrange(1,6):
-		supplier = args.get("supplier_" + str(i))
-		if supplier:
-			try:
-				doc = frappe.get_doc({
-					"doctype":"Supplier",
-					"supplier_name": supplier,
-					"supplier_type": _("Local"),
-					"company": args.get("company_name").strip()
-				}).insert()
+    for i in xrange(1,6):
+        supplier = args.get("supplier_" + str(i))
+        if supplier:
+            try:
+                doc = frappe.get_doc({
+                    "doctype":"Supplier",
+                    "supplier_name": supplier,
+                    "supplier_type": _("Local"),
+                    "company": args.get("company_name").strip()
+                }).insert()
 
-				if args.get("supplier_contact_" + str(i)):
-					create_contact(args.get("supplier_contact_" + str(i)),
-						"supplier", doc.name)
-			except frappe.NameError:
-				pass
+                if args.get("supplier_contact_" + str(i)):
+                    create_contact(args.get("supplier_contact_" + str(i)),
+                        "supplier", doc.name)
+            except frappe.NameError:
+                pass
 
 def create_contact(contact, party_type, party):
-	"""Create contact based on given contact name"""
-	contact = contact.strip().split(" ")
+    """Create contact based on given contact name"""
+    contact = contact.strip().split(" ")
 
-	frappe.get_doc({
-		"doctype":"Contact",
-		party_type: party,
-		"first_name":contact[0],
-		"last_name": len(contact) > 1 and contact[1] or ""
-	}).insert()
+    frappe.get_doc({
+        "doctype":"Contact",
+        party_type: party,
+        "first_name":contact[0],
+        "last_name": len(contact) > 1 and contact[1] or ""
+    }).insert()
 
 def create_letter_head(args):
-	if args.get("attach_letterhead"):
-		frappe.get_doc({
-			"doctype":"Letter Head",
-			"letter_head_name": _("Standard"),
-			"is_default": 1
-		}).insert()
+    if args.get("attach_letterhead"):
+        frappe.get_doc({
+            "doctype":"Letter Head",
+            "letter_head_name": _("Standard"),
+            "is_default": 1
+        }).insert()
 
-		attach_letterhead = args.get("attach_letterhead").split(",")
-		if len(attach_letterhead)==3:
-			filename, filetype, content = attach_letterhead
-			fileurl = save_file(filename, content, "Letter Head", _("Standard"), decode=True).file_url
-			frappe.db.set_value("Letter Head", _("Standard"), "content", "<img src='%s' style='max-width: 100%%;'>" % fileurl)
+        attach_letterhead = args.get("attach_letterhead").split(",")
+        if len(attach_letterhead)==3:
+            filename, filetype, content = attach_letterhead
+            fileurl = save_file(filename, content, "Letter Head", _("Standard"), decode=True).file_url
+            frappe.db.set_value("Letter Head", _("Standard"), "content", "<img src='%s' style='max-width: 100%%;'>" % fileurl)
 
 def create_logo(args):
-	if args.get("attach_logo"):
-		attach_logo = args.get("attach_logo").split(",")
-		if len(attach_logo)==3:
-			filename, filetype, content = attach_logo
-			fileurl = save_file(filename, content, "Website Settings", "Website Settings",
-				decode=True).file_url
-			frappe.db.set_value("Website Settings", "Website Settings", "brand_html",
-				"<img src='{0}' style='max-width: 40px; max-height: 25px;'> {1}".format(fileurl, args.get("company_name").strip()))
+    if args.get("attach_logo"):
+        attach_logo = args.get("attach_logo").split(",")
+        if len(attach_logo)==3:
+            filename, filetype, content = attach_logo
+            fileurl = save_file(filename, content, "Website Settings", "Website Settings",
+                decode=True).file_url
+            frappe.db.set_value("Website Settings", "Website Settings", "brand_html",
+                "<img src='{0}' style='max-width: 40px; max-height: 25px;'> {1}".format(fileurl, args.get("company_name").strip()))
 
 def create_territories():
-	"""create two default territories, one for home country and one named Rest of the World"""
-	from frappe.utils.nestedset import get_root_of
-	country = frappe.db.get_default("country")
-	root_territory = get_root_of("Territory")
-	for name in (country, _("Rest Of The World")):
-		if name and not frappe.db.exists("Territory", name):
-			frappe.get_doc({
-				"doctype": "Territory",
-				"territory_name": name.replace("'", ""),
-				"parent_territory": root_territory,
-				"is_group": "No"
-			}).insert()
+    """create two default territories, one for home country and one named Rest of the World"""
+    from frappe.utils.nestedset import get_root_of
+    country = frappe.db.get_default("country")
+    root_territory = get_root_of("Territory")
+    for name in (country, _("Rest Of The World")):
+        if name and not frappe.db.exists("Territory", name):
+            frappe.get_doc({
+                "doctype": "Territory",
+                "territory_name": name.replace("'", ""),
+                "parent_territory": root_territory,
+                "is_group": "No"
+            }).insert()
 
 def login_as_first_user(args):
-	if args.get("email") and hasattr(frappe.local, "login_manager"):
-		frappe.local.login_manager.login_as(args.get("email"))
+    if args.get("email") and hasattr(frappe.local, "login_manager"):
+        frappe.local.login_manager.login_as(args.get("email"))
 
 def create_users(args):
-	if frappe.session.user == 'Administrator':
-		return
+    if frappe.session.user == 'Administrator':
+        return
 
-	# create employee for self
-	emp = frappe.get_doc({
-		"doctype": "Employee",
-		"employee_name": " ".join(filter(None, [args.get("first_name"), args.get("last_name")])),
-		"user_id": frappe.session.user,
-		"status": "Active",
-		"company": args.get("company_name")
-	})
-	emp.flags.ignore_mandatory = True
-	emp.insert(ignore_permissions = True)
+    # create employee for self
+    emp = frappe.get_doc({
+        "doctype": "Employee",
+        "employee_name": " ".join(filter(None, [args.get("first_name"), args.get("last_name")])),
+        "user_id": frappe.session.user,
+        "status": "Active",
+        "company": args.get("company_name")
+    })
+    emp.flags.ignore_mandatory = True
+    emp.insert(ignore_permissions = True)
 
-	for i in xrange(1,5):
-		email = args.get("user_email_" + str(i))
-		fullname = args.get("user_fullname_" + str(i))
-		if email:
-			if not fullname:
-				fullname = email.split("@")[0]
+    for i in xrange(1,5):
+        email = args.get("user_email_" + str(i))
+        fullname = args.get("user_fullname_" + str(i))
+        if email:
+            if not fullname:
+                fullname = email.split("@")[0]
 
-			parts = fullname.split(" ", 1)
+            parts = fullname.split(" ", 1)
 
-			user = frappe.get_doc({
-				"doctype": "User",
-				"email": email,
-				"first_name": parts[0],
-				"last_name": parts[1] if len(parts) > 1 else "",
-				"enabled": 1,
-				"user_type": "System User"
-			})
+            user = frappe.get_doc({
+                "doctype": "User",
+                "email": email,
+                "first_name": parts[0],
+                "last_name": parts[1] if len(parts) > 1 else "",
+                "enabled": 1,
+                "user_type": "System User"
+            })
 
-			# default roles
-			user.append_roles("Projects User", "Stock User", "Support Team")
+            # default roles
+            user.append_roles("Projects User", "Stock User", "Support Team")
 
-			if args.get("user_sales_" + str(i)):
-				user.append_roles("Sales User", "Sales Manager", "Accounts User")
-			if args.get("user_purchaser_" + str(i)):
-				user.append_roles("Purchase User", "Purchase Manager", "Accounts User")
-			if args.get("user_accountant_" + str(i)):
-				user.append_roles("Accounts Manager", "Accounts User")
+            if args.get("user_sales_" + str(i)):
+                user.append_roles("Sales User", "Sales Manager", "Accounts User")
+            if args.get("user_purchaser_" + str(i)):
+                user.append_roles("Purchase User", "Purchase Manager", "Accounts User")
+            if args.get("user_accountant_" + str(i)):
+                user.append_roles("Accounts Manager", "Accounts User")
 
-			user.flags.delay_emails = True
+            user.flags.delay_emails = True
 
-			if not frappe.db.get_value("User", email):
-				user.insert(ignore_permissions=True)
+            if not frappe.db.get_value("User", email):
+                user.insert(ignore_permissions=True)
 
-				# create employee
-				emp = frappe.get_doc({
-					"doctype": "Employee",
-					"employee_name": fullname,
-					"user_id": email,
-					"status": "Active",
-					"company": args.get("company_name")
-				})
-				emp.flags.ignore_mandatory = True
-				emp.insert(ignore_permissions = True)
+                # create employee
+                emp = frappe.get_doc({
+                    "doctype": "Employee",
+                    "employee_name": fullname,
+                    "user_id": email,
+                    "status": "Active",
+                    "company": args.get("company_name")
+                })
+                emp.flags.ignore_mandatory = True
+                emp.insert(ignore_permissions = True)
 
 def create_academic_term():
-	at = ["Semester 1", "Semester 2", "Semester 3"]
-	for d in at:
-		academic_term = frappe.new_doc("Academic Term")
-		academic_term.term_name = d
-		academic_term.save()
+    at = ["Semester 1", "Semester 2", "Semester 3"]
+    ay = ["2013-14", "2014-15", "2015-16", "2016-17", "2017-18"]
+    for y in ay:
+        for t in at:
+            academic_term = frappe.new_doc("Academic Term")
+            academic_term.academic_year = y
+            academic_term.term_name = t
+            academic_term.save()
 
 def create_academic_year():
-	ac = ["2013-14", "2014-15", "2015-16", "2016-17", "2017-18"]
-	for d in ac:
-		academic_year = frappe.new_doc("Academic Year")
-		academic_year.academic_year_name = d
-		academic_year.save()
+    ac = ["2013-14", "2014-15", "2015-16", "2016-17", "2017-18"]
+    for d in ac:
+        academic_year = frappe.new_doc("Academic Year")
+        academic_year.academic_year_name = d
+        academic_year.save()
 
 def create_program(args):
-	for i in xrange(1,6):
-		if args.get("program_" + str(i)):
-			program = frappe.new_doc("Program")
-			program.program_name = args.get("program_" + str(i))
-			program.save()
+    for i in xrange(1,6):
+        if args.get("program_" + str(i)):
+            program = frappe.new_doc("Program")
+            program.program_name = args.get("program_" + str(i))
+            program.save()
 
 def create_course(args):
-	for i in xrange(1,6):
-		if args.get("course_" + str(i)):
-			course = frappe.new_doc("Course")
-			course.course_name = args.get("course_" + str(i))
-			course.save()
+    for i in xrange(1,6):
+        if args.get("course_" + str(i)):
+            course = frappe.new_doc("Course")
+            course.course_name = args.get("course_" + str(i))
+            course.save()
 
 def create_instructor(args):
-	for i in xrange(1,6):
-		if args.get("instructor_" + str(i)):
-			instructor = frappe.new_doc("Instructor")
-			instructor.instructor_name = args.get("instructor_" + str(i))
-			instructor.save()
+    for i in xrange(1,6):
+        if args.get("instructor_" + str(i)):
+            instructor = frappe.new_doc("Instructor")
+            instructor.instructor_name = args.get("instructor_" + str(i))
+            instructor.save()
 
 def create_room(args):
-	for i in xrange(1,6):
-		if args.get("room_" + str(i)):
-			room = frappe.new_doc("Room")
-			room.room_name = args.get("room_" + str(i))
-			room.seating_capacity = args.get("room_capacity_" + str(i))
-			room.save()
+    for i in xrange(1,6):
+        if args.get("room_" + str(i)):
+            room = frappe.new_doc("Room")
+            room.room_name = args.get("room_" + str(i))
+            room.seating_capacity = args.get("room_capacity_" + str(i))
+            room.save()
 
 
diff --git a/patches.txt b/patches.txt
new file mode 100644
index 0000000..8f127fe
--- /dev/null
+++ b/patches.txt
@@ -0,0 +1 @@
+bench.patches.v3.deprecate_old_config