Assessment Module Report (#12605)

* updated course wise assessment report

* added new report Final assessment grades
diff --git a/erpnext/education/api.py b/erpnext/education/api.py
index ea4da69..99fb36e 100644
--- a/erpnext/education/api.py
+++ b/erpnext/education/api.py
@@ -269,7 +269,10 @@
 	:param Percentage: Score Percentage Percentage
 	"""
 	grading_scale_intervals = {}
-	for d in frappe.get_all("Grading Scale Interval", fields=["grade_code", "threshold"], filters={"parent": grading_scale}):
+	if not hasattr(frappe.local, 'grading_scale'):
+		grading_scale = frappe.get_all("Grading Scale Interval", fields=["grade_code", "threshold"], filters={"parent": grading_scale})
+		frappe.local.grading_scale = grading_scale
+	for d in frappe.local.grading_scale:
 		grading_scale_intervals.update({d.threshold:d.grade_code})
 	intervals = sorted(grading_scale_intervals.keys(), key=float, reverse=True)
 	for interval in intervals:
diff --git a/erpnext/education/doctype/assessment_criteria/assessment_criteria.py b/erpnext/education/doctype/assessment_criteria/assessment_criteria.py
index e666a74..eadc0de 100644
--- a/erpnext/education/doctype/assessment_criteria/assessment_criteria.py
+++ b/erpnext/education/doctype/assessment_criteria/assessment_criteria.py
@@ -6,5 +6,9 @@
 import frappe
 from frappe.model.document import Document
 
+STD_CRITERIA = ["total", "total score", "total grade", "maximum score", "score", "grade"]
+
 class AssessmentCriteria(Document):
-	pass
+	def validate(self):
+		if self.assessment_criteria.lower() in STD_CRITERIA:
+			frappe.throw("Can't create standard criteria. Please rename the criteria")
\ No newline at end of file
diff --git a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.html b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.html
index 60300b0..e46a5e7 100644
--- a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.html
+++ b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.html
@@ -6,9 +6,15 @@
 {% } %}
 <h4 class="text-center">{%= __("Assessment Report") %}</h4>
 <hr>
+<h5 class="text-center">{%= __("Academic Year: ") %} {%= filters.academic_year %} </h5>
+{% if (filters.academic_term){ %}
+<h5 class="text-center">{%= __("Academic Term: ") %} {%= filters.academic_term %} </h5>
+{% } %}
 <h5 class="text-center">{%= __("Course Code: ") %} {%= filters.course %}</h5>
 <h5 class="text-center">{%= __("Assessment Group: ") %} {%= filters.assessment_group %}</h5>
-<h5 class="text-center">{%= __("Assessment Plan: ") %} {%= data_to_be_printed[0]["assessment_plan"] %} </h5>
+{% if (filters.student_group){ %}
+<h5 class="text-center">{%= __("Student Group: ") %} {%= filters.student_group %} </h5>
+{% } %}
 <hr>
 
 <table class="table table-bordered">
diff --git a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.js b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.js
index 42b19eb..8c42d48 100644
--- a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.js
+++ b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.js
@@ -4,18 +4,17 @@
 frappe.query_reports["Course wise Assessment Report"] = {
 	"filters": [
 		{
-			"fieldname":"assessment_group",
-			"label": __("Assessment Group"),
+			"fieldname":"academic_year",
+			"label": __("Academic Year"),
 			"fieldtype": "Link",
-			"options": "Assessment Group",
-			"reqd": 1,
-			"get_query": function() {
-				return{
-					filters: {
-						'is_group': 0
-					}
-				};
-			}
+			"options": "Academic Year",
+			"reqd": 1
+		},
+		{
+			"fieldname":"academic_term",
+			"label": __("Academic Term"),
+			"fieldtype": "Link",
+			"options": "Academic Term"
 		},
 		{
 			"fieldname":"course",
@@ -29,6 +28,13 @@
 			"label": __("Student Group"),
 			"fieldtype": "Link",
 			"options": "Student Group"
+		},
+		{
+			"fieldname":"assessment_group",
+			"label": __("Assessment Group"),
+			"fieldtype": "Link",
+			"options": "Assessment Group",
+			"reqd": 1
 		}
 	]
 };
diff --git a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py
index ff17238..a50ad7b 100644
--- a/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py
+++ b/erpnext/education/report/course_wise_assessment_report/course_wise_assessment_report.py
@@ -5,129 +5,189 @@
 import frappe
 from frappe import _
 from frappe.utils import flt
-from collections import defaultdict
+from collections import defaultdict, OrderedDict
 from erpnext.education.api import get_grade
 
 
 def execute(filters=None):
-	data = []
-
+	data, chart, grades = [], [], []
 	args = frappe._dict()
+	grade_wise_analysis = defaultdict(dict)
+
+	args["academic_year"] = filters.get("academic_year")
+	args["course"] = filters.get("course")
 	args["assessment_group"] = filters.get("assessment_group")
+
+	args["academic_term"] = filters.get("academic_term")
+	args["student_group"] = filters.get("student_group")
+
 	if args["assessment_group"] == "All Assessment Groups":
 		frappe.throw(_("Please select the assessment group other than 'All Assessment Groups'"))
 
-	args["course"] = filters.get("course")
-	args["student_group"] = filters.get("student_group")
+	returned_values = get_formatted_result(args, get_assessment_criteria=True)
+	student_dict = returned_values["student_details"]
+	result_dict = returned_values["assessment_result"]
+	assessment_criteria_dict = returned_values["assessment_criteria"]
+
+	for student in result_dict:
+		student_row = {}
+		student_row["student"] = student
+		student_row["student_name"] = student_dict[student]
+		for criteria in assessment_criteria_dict:
+			scrub_criteria = frappe.scrub(criteria)
+			if criteria in result_dict[student][args.course][args.assessment_group]:
+				student_row[scrub_criteria] = result_dict[student][args.course][args.assessment_group][criteria]["grade"]
+				student_row[scrub_criteria + "_score"] = result_dict[student][args.course][args.assessment_group][criteria]["score"]
+
+				# create the list of possible grades
+				if student_row[scrub_criteria] not in grades:
+					grades.append(student_row[scrub_criteria])
+				
+				# create the dict of for gradewise analysis
+				if student_row[scrub_criteria] not in grade_wise_analysis[criteria]:
+					grade_wise_analysis[criteria][student_row[scrub_criteria]] = 1
+				else:
+					grade_wise_analysis[criteria][student_row[scrub_criteria]] += 1
+			else:
+				student_row[frappe.scrub(criteria)] = ""
+				student_row[frappe.scrub(criteria)+ "_score"] = ""
+		data.append(student_row)
+
+	assessment_criteria_list = [d for d in assessment_criteria_dict]
+	columns = get_column(assessment_criteria_dict)
+	chart = get_chart_data(grades, assessment_criteria_list, grade_wise_analysis)
+
+	return columns, data, None, chart
 
 
-	# find all assessment plan and related details linked with the given filters
-	def get_assessment_details():
-		if args["student_group"]:
-			cond = "and ap.student_group=%(student_group)s"
+def get_formatted_result(args, get_assessment_criteria=False, get_course=False):
+	cond, cond1, cond2, cond3, cond4 = " ", " ", " ", " ", " "
+	args_list = [args.academic_year]
+
+	if args.course:
+		cond = " and ar.course=%s"
+		args_list.append(args.course)
+
+	if args.academic_term:
+		cond1 = " and ar.academic_term=%s"
+		args_list.append(args.academic_term)
+
+	if args.student_group:
+		cond2 = " and ar.student_group=%s"
+		args_list.append(args.student_group)
+
+	create_total_dict = False
+	group_type = frappe.get_value("Assessment Group", args.assessment_group, "is_group")
+	if group_type:
+		from frappe.desk.treeview import get_children
+		assessment_groups = [d.get("value") for d in get_children("Assessment Group",
+			args.assessment_group) if d.get("value") and not d.get("expandable")]
+		cond3 = " and ar.assessment_group in (%s)"%(', '.join(['%s']*len(assessment_groups)))
+	else:
+		assessment_groups = [args.assessment_group]
+		cond3 = " and ar.assessment_group=%s"
+	args_list += assessment_groups
+
+	if args.students:
+		cond4 = " and ar.student in (%s)"%(', '.join(['%s']*len(args.students)))
+		args_list += args.students
+
+	assessment_result = frappe.db.sql('''
+		SELECT
+			ar.student, ar.student_name, ar.academic_year, ar.academic_term, ar.program, ar.course,
+			ar.assessment_plan, ar.grading_scale, ar.assessment_group, ar.student_group,
+			ard.assessment_criteria, ard.maximum_score, ard.grade, ard.score
+		FROM
+			`tabAssessment Result` ar, `tabAssessment Result Detail` ard
+		WHERE
+			ar.name=ard.parent and ar.docstatus=1 and ar.academic_year=%s {0} {1} {2} {3} {4}
+		ORDER BY
+			ard.assessment_criteria'''.format(cond, cond1, cond2, cond3, cond4),
+		tuple(args_list), as_dict=1)
+
+	# create the nested dictionary structure as given below:
+	# <variable_name>.<student_name>.<course>.<assessment_group>.<assessment_criteria>.<grade/score/max_score>
+	# "Total Score" -> assessment criteria used for totaling and args.assessment_group -> for totaling all the assesments
+
+	student_details = {}
+	formatted_assessment_result = defaultdict(dict)
+	assessment_criteria_dict = OrderedDict()
+	course_dict = OrderedDict()
+	total_maximum_score = None
+	if not (len(assessment_groups) == 1 and assessment_groups[0] == args.assessment_group):
+		create_total_dict = True
+
+	# add the score for a given score and recalculate the grades
+	def add_score_and_recalculate_grade(result, assessment_group, assessment_criteria):
+		formatted_assessment_result[result.student][result.course][assessment_group]\
+			[assessment_criteria]["maximum_score"] += result.maximum_score
+		formatted_assessment_result[result.student][result.course][assessment_group]\
+			[assessment_criteria]["score"] += result.score
+		tmp_grade = get_grade(result.grading_scale, ((formatted_assessment_result[result.student][result.course]
+			[assessment_group][assessment_criteria]["score"])/(formatted_assessment_result[result.student]
+			[result.course][assessment_group][assessment_criteria]["maximum_score"]))*100)
+		formatted_assessment_result[result.student][result.course][assessment_group]\
+			[assessment_criteria]["grade"] = tmp_grade
+
+	# create the assessment criteria "Total Score" with the sum of all the scores of the assessment criteria in a given assessment group
+	def add_total_score(result, assessment_group):
+		if "Total Score" not in formatted_assessment_result[result.student][result.course][assessment_group]:
+			formatted_assessment_result[result.student][result.course][assessment_group]["Total Score"] = frappe._dict({
+				"assessment_criteria": "Total Score", "maximum_score": result.maximum_score, "score": result.score, "grade": result.grade})
 		else:
-			cond = ''
+			add_score_and_recalculate_grade(result, assessment_group, "Total Score")
 
-		assessment_plan = frappe.db.sql('''
-			select
-				ap.name, ap.student_group, ap.grading_scale, apc.assessment_criteria, apc.maximum_score as max_score
-			from
-				`tabAssessment Plan` ap, `tabAssessment Plan Criteria` apc
-			where
-				ap.assessment_group=%(assessment_group)s and ap.course=%(course)s and
-				ap.name=apc.parent and ap.docstatus=1 {0}
-			order by
-				apc.assessment_criteria'''.format(cond), (args), as_dict=1)
+	for result in assessment_result:
+		if result.student not in student_details:
+			student_details[result.student] = result.student_name
 
-		assessment_plan_list = list(set([d["name"] for d in assessment_plan]))
-		if not assessment_plan_list:
-			frappe.throw(_("No assessment plan linked with this assessment group"))
+		assessment_criteria_details = frappe._dict({"assessment_criteria": result.assessment_criteria,
+			"maximum_score": result.maximum_score, "score": result.score, "grade": result.grade})
 
-		assessment_criteria_list = list(set([(d["assessment_criteria"],d["max_score"]) for d in assessment_plan]))
-		student_group_list = list(set([d["student_group"] for d in assessment_plan]))
-		total_maximum_score = flt(sum([flt(d[1]) for d in assessment_criteria_list]))
-		grading_scale = assessment_plan[0]["grading_scale"]
+		if not formatted_assessment_result[result.student]:
+			formatted_assessment_result[result.student] = defaultdict(dict)
+		if not formatted_assessment_result[result.student][result.course]:
+			formatted_assessment_result[result.student][result.course] = defaultdict(dict)
 
-		return assessment_plan_list, assessment_criteria_list, total_maximum_score, grading_scale, student_group_list
+		if not create_total_dict:
+			formatted_assessment_result[result.student][result.course][result.assessment_group]\
+				[result.assessment_criteria] = assessment_criteria_details
+			add_total_score(result, result.assessment_group)
+
+		# create the total of all the assessment groups criteria-wise
+		elif create_total_dict:
+			if not formatted_assessment_result[result.student][result.course][args.assessment_group]:
+				formatted_assessment_result[result.student][result.course][args.assessment_group] = defaultdict(dict)
+				formatted_assessment_result[result.student][result.course][args.assessment_group]\
+					[result.assessment_criteria] = assessment_criteria_details
+			elif result.assessment_criteria not in formatted_assessment_result[result.student][result.course][args.assessment_group]:
+				formatted_assessment_result[result.student][result.course][args.assessment_group]\
+					[result.assessment_criteria] = assessment_criteria_details
+			elif result.assessment_criteria in formatted_assessment_result[result.student][result.course][args.assessment_group]:
+				add_score_and_recalculate_grade(result, args.assessment_group, result.assessment_criteria)
+
+			add_total_score(result, args.assessment_group)
+
+		total_maximum_score = formatted_assessment_result[result.student][result.course][args.assessment_group]\
+			["Total Score"]["maximum_score"]
+		if get_assessment_criteria:
+			assessment_criteria_dict[result.assessment_criteria] = formatted_assessment_result[result.student][result.course]\
+				[args.assessment_group][result.assessment_criteria]["maximum_score"]
+		if get_course:
+			course_dict[result.course] = total_maximum_score
+
+	if get_assessment_criteria and total_maximum_score:
+		assessment_criteria_dict["Total Score"] = total_maximum_score
+
+	return {
+		"student_details": student_details,
+		"assessment_result": formatted_assessment_result,
+		"assessment_criteria": assessment_criteria_dict,
+		"course_dict": course_dict
+	}
 
 
-	# get all the result and make a dict map student as the key and value as dict of result
-	def get_result_map():
-		result_dict = defaultdict(dict)
-		kounter = defaultdict(dict)
-		assessment_result = frappe.db.sql('''select ar.student, ard.assessment_criteria, ard.grade, ard.score
-			from `tabAssessment Result` ar, `tabAssessment Result Detail` ard
-			where ar.assessment_plan in (%s) and ar.name=ard.parent and ar.docstatus=1
-			order by ard.assessment_criteria''' %', '.join(['%s']*len(assessment_plan_list)),
-			tuple(assessment_plan_list), as_dict=1)
-
-		for result in assessment_result:
-			if "total_score" in result_dict[result.student]:
-				total_score = result_dict[result.student]["total_score"] + result.score
-			else:
-				total_score = result.score
-			total = get_grade(grading_scale, (total_score/total_maximum_score)*100)
-
-			if result.grade in kounter[result.assessment_criteria]:
-				kounter[result.assessment_criteria][result.grade] += 1
-			else:
-				kounter[result.assessment_criteria].update({result.grade: 1})
-
-			if "Total" not in kounter:
-				kounter["Total"] = {}
-
-			if "total" in result_dict[result.student]:
-				prev_grade = result_dict[result.student]["total"]
-				prev_grade_count = kounter["Total"].get(prev_grade) - 1
-				kounter["Total"].update({prev_grade: prev_grade_count})
-			latest_grade_count = kounter["Total"].get(total)+1 if kounter["Total"].get(total) else 1
-			kounter["Total"].update({total: latest_grade_count})
-
-			result_dict[result.student].update({
-					frappe.scrub(result.assessment_criteria): result.grade,
-					frappe.scrub(result.assessment_criteria)+"_score": result.score,
-					"total_score": total_score,
-					"total": total
-				})
-
-		return result_dict, kounter
-
-	# make data from the result dict
-	def get_data():
-		student_list = frappe.db.sql('''select sgs.student, sgs.student_name
-			from `tabStudent Group` sg, `tabStudent Group Student` sgs
-			where sg.name = sgs.parent and sg.name in (%s)
-			order by sgs.group_roll_number asc''' %', '.join(['%s']*len(student_group_list)),
-			tuple(student_group_list), as_dict=1)
-
-		for student in student_list:
-			student.update(result_dict[student.student])
-		return student_list
-
-
-	# get chart data
-	def get_chart():
-		grading_scale = frappe.db.get_value("Assessment Plan", list(assessment_plan_list)[0], "grading_scale")
-		grades = frappe.db.sql_list('''select grade_code from `tabGrading Scale Interval` where parent=%s''',
-			(grading_scale))
-		criteria_list = [d[0] for d in assessment_criteria_list] + ["Total"]
-		return get_chart_data(grades, criteria_list, kounter)
-
-
-	assessment_plan_list, assessment_criteria_list, total_maximum_score, grading_scale,\
-		student_group_list = get_assessment_details()
-	result_dict, kounter = get_result_map()
-	data = get_data()
-
-	columns = get_column(assessment_criteria_list, total_maximum_score)
-	chart = get_chart()
-	data_to_be_printed = [{
-		"assessment_plan": ", ".join(assessment_plan_list)
-	}]
-
-	return columns, data, None, chart, data_to_be_printed
-
-def get_column(assessment_criteria, total_maximum_score):
+def get_column(assessment_criteria):
 	columns = [{
 		"fieldname": "student",
 		"label": _("Student ID"),
@@ -143,40 +203,28 @@
 	}]
 	for d in assessment_criteria:
 		columns.append({
-			"fieldname": frappe.scrub(d[0]),
-			"label": d[0],
+			"fieldname": frappe.scrub(d),
+			"label": d,
 			"fieldtype": "Data",
 			"width": 110
 		})
 		columns.append({
-			"fieldname": frappe.scrub(d[0]) +"_score",
-			"label": "Score(" + str(int(d[1])) + ")",
+			"fieldname": frappe.scrub(d) +"_score",
+			"label": "Score(" + str(int(assessment_criteria[d])) + ")",
 			"fieldtype": "Float",
 			"width": 100
 		})
 
-	columns += [{
-		"fieldname": "total",
-		"label": "Total",
-		"fieldtype": "Data",
-		"width": 100
-	},
-	{
-		"fieldname": "total_score",
-		"label": "Total Score("+ str(int(total_maximum_score)) + ")",
-		"fieldtype": "Float",
-		"width": 110
-	}]
-
 	return columns
 
-def get_chart_data(grades, assessment_criteria_list, kounter):
+
+def get_chart_data(grades, criteria_list, kounter):
 	grades = sorted(grades)
 	datasets = []
 
 	for grade in grades:
 		tmp = frappe._dict({"values":[], "title": grade})
-		for criteria in assessment_criteria_list:
+		for criteria in criteria_list:
 			if grade in kounter[criteria]:
 				tmp["values"].append(kounter[criteria][grade])
 			else:
@@ -185,7 +233,7 @@
 
 	return {
 		"data": {
-			"labels": assessment_criteria_list,
+			"labels": criteria_list,
 			"datasets": datasets
 		},
 		"type": 'bar',
diff --git a/erpnext/education/report/final_assessment_grades/__init__.py b/erpnext/education/report/final_assessment_grades/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/education/report/final_assessment_grades/__init__.py
diff --git a/erpnext/education/report/final_assessment_grades/final_assessment_grades.js b/erpnext/education/report/final_assessment_grades/final_assessment_grades.js
new file mode 100644
index 0000000..ba0a42f
--- /dev/null
+++ b/erpnext/education/report/final_assessment_grades/final_assessment_grades.js
@@ -0,0 +1,38 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Final Assessment Grades"] = {
+	"filters": [
+		{
+			"fieldname":"academic_year",
+			"label": __("Academic Year"),
+			"fieldtype": "Link",
+			"options": "Academic Year",
+			"reqd": 1
+		},
+		{
+			"fieldname":"student_group",
+			"label": __("Student Group"),
+			"fieldtype": "Link",
+			"options": "Student Group",
+			"reqd": 1,
+			"get_query": function() {
+				return{
+					filters: {
+						"group_based_on": "Batch",
+						"academic_year": frappe.query_report_filters_by_name.academic_year.value
+					}
+				};
+			}
+		},
+		{
+			"fieldname":"assessment_group",
+			"label": __("Assessment Group"),
+			"fieldtype": "Link",
+			"options": "Assessment Group",
+			"reqd": 1
+		}
+
+	]
+}
diff --git a/erpnext/education/report/final_assessment_grades/final_assessment_grades.json b/erpnext/education/report/final_assessment_grades/final_assessment_grades.json
new file mode 100644
index 0000000..1efbb6e
--- /dev/null
+++ b/erpnext/education/report/final_assessment_grades/final_assessment_grades.json
@@ -0,0 +1,20 @@
+{
+ "add_total_row": 0, 
+ "apply_user_permissions": 1, 
+ "creation": "2018-01-22 17:04:43.412054", 
+ "disabled": 0, 
+ "docstatus": 0, 
+ "doctype": "Report", 
+ "idx": 0, 
+ "is_standard": "Yes", 
+ "letter_head": "Shishuvan Secondary School", 
+ "modified": "2018-01-22 17:04:43.412054", 
+ "modified_by": "Administrator", 
+ "module": "Education", 
+ "name": "Final Assessment Grades", 
+ "owner": "Administrator", 
+ "ref_doctype": "Assessment Result", 
+ "report_name": "Final Assessment Grades", 
+ "report_type": "Script Report", 
+ "roles": []
+}
\ No newline at end of file
diff --git a/erpnext/education/report/final_assessment_grades/final_assessment_grades.py b/erpnext/education/report/final_assessment_grades/final_assessment_grades.py
new file mode 100644
index 0000000..efc9aff
--- /dev/null
+++ b/erpnext/education/report/final_assessment_grades/final_assessment_grades.py
@@ -0,0 +1,85 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from collections import defaultdict
+
+from erpnext.education.report.course_wise_assessment_report.course_wise_assessment_report import get_formatted_result
+from erpnext.education.report.course_wise_assessment_report.course_wise_assessment_report import get_chart_data
+
+
+def execute(filters=None):
+	columns, data, grades = [], [], []
+	args = frappe._dict()
+	course_wise_analysis = defaultdict(dict)
+
+	args["academic_year"] = filters.get("academic_year")
+	assessment_group = args["assessment_group"] = filters.get("assessment_group")
+
+	student_group = filters.get("student_group")
+	args.students = frappe.db.sql_list("select student from `tabStudent Group Student` where parent=%s", (student_group))
+
+	values = get_formatted_result(args, get_course=True)
+	student_details = values.get("student_details")
+	assessment_result = values.get("assessment_result")
+	course_dict = values.get("course_dict")
+
+	for student in args.students:
+		student_row = {}
+		student_row["student"] = student
+		student_row["student_name"] = student_details[student]
+		for course in course_dict:
+			scrub_course = frappe.scrub(course)
+			if assessment_group in assessment_result[student][course]:
+				student_row["grade_" + scrub_course] = assessment_result[student][course][assessment_group]["Total Score"]["grade"]
+				student_row["score_" + scrub_course] = assessment_result[student][course][assessment_group]["Total Score"]["score"]
+
+				# create the list of possible grades
+				if student_row["grade_" + scrub_course] not in grades:
+					grades.append(student_row["grade_" + scrub_course])
+
+				# create the dict of for gradewise analysis
+				if student_row["grade_" + scrub_course] not in course_wise_analysis[course]:
+					course_wise_analysis[course][student_row["grade_" + scrub_course]] = 1
+				else:
+					course_wise_analysis[course][student_row["grade_" + scrub_course]] += 1
+
+		data.append(student_row)
+
+	course_list = [d for d in course_dict]
+	columns = get_column(course_dict)
+	chart = get_chart_data(grades, course_list, course_wise_analysis)
+	return columns, data, None, chart
+
+
+def get_column(course_dict):
+	columns = [{
+		"fieldname": "student",
+		"label": _("Student ID"),
+		"fieldtype": "Link",
+		"options": "Student",
+		"width": 90
+	},
+	{
+		"fieldname": "student_name",
+		"label": _("Student Name"),
+		"fieldtype": "Data",
+		"width": 160
+	}]
+	for course in course_dict:
+		columns.append({
+			"fieldname": "grade_" + frappe.scrub(course),
+			"label": course,
+			"fieldtype": "Data",
+			"width": 110
+		})
+		columns.append({
+			"fieldname": "score_" + frappe.scrub(course),
+			"label": "Score(" + str(course_dict[course]) + ")",
+			"fieldtype": "Float",
+			"width": 100
+		})
+
+	return columns