')
+ .appendTo(frm.fields_dict.students_html.wrapper);
+ },
+ onload: function(frm) {
+ frm.set_query("student_group", function() {
+ return {
+ "filters": {
+ "group_based_on": frm.doc.group_based_on,
+ "disabled": 0
+ }
+ };
+ });
+ },
+
+ refresh: function(frm) {
+ if (xhiveframework.route_options) {
+ frm.set_value("based_on", xhiveframework.route_options.based_on);
+ frm.set_value("student_group", xhiveframework.route_options.student_group);
+ frm.set_value("course_schedule", xhiveframework.route_options.course_schedule);
+ xhiveframework.route_options = null;
+ }
+ frm.disable_save();
+ },
+
+ based_on: function(frm) {
+ if (frm.doc.based_on == "Student Group") {
+ frm.set_value("course_schedule", "");
+ } else {
+ frm.set_value("student_group", "");
+ }
+ },
+
+ student_group: function(frm) {
+ if ((frm.doc.student_group && frm.doc.date) || frm.doc.course_schedule) {
+ frm.students_area.find('.student-attendance-checks').html(`
Fetching...
`);
+ var method = "education.education.doctype.student_attendance_tool.student_attendance_tool.get_student_attendance_records";
+
+ xhiveframework.call({
+ method: method,
+ args: {
+ based_on: frm.doc.based_on,
+ student_group: frm.doc.student_group,
+ date: frm.doc.date,
+ course_schedule: frm.doc.course_schedule
+ },
+ callback: function(r) {
+ frm.events.get_students(frm, r.message);
+ }
+ })
+ }
+ },
+
+ date: function(frm) {
+ if (frm.doc.date > xhiveframework.datetime.get_today())
+ xhiveframework.throw(__("Cannot mark attendance for future dates."));
+ frm.trigger("student_group");
+ },
+
+ course_schedule: function(frm) {
+ frm.trigger("student_group");
+ },
+
+ get_students: function(frm, students) {
+ students = students || [];
+ frm.students_editor = new education.StudentsEditor(frm, frm.students_area, students);
+ }
+});
+
+
+education.StudentsEditor = class StudentsEditor {
+ constructor(frm, wrapper, students) {
+ this.wrapper = wrapper;
+ this.frm = frm;
+ if(students.length > 0) {
+ this.make(frm, students);
+ } else {
+ this.show_empty_state();
+ }
+ }
+ make(frm, students) {
+ var me = this;
+
+ $(this.wrapper).empty();
+ var student_toolbar = $('
\
+ \
+ \
+
').appendTo($(this.wrapper));
+
+ student_toolbar.find(".btn-add")
+ .html(__('Check all'))
+ .on("click", function() {
+ $(me.wrapper).find('input[type="checkbox"]').each(function(i, check) {
+ if (!$(check).prop("disabled")) {
+ check.checked = true;
+ }
+ });
+ });
+
+ student_toolbar.find(".btn-remove")
+ .html(__('Uncheck all'))
+ .on("click", function() {
+ $(me.wrapper).find('input[type="checkbox"]').each(function(i, check) {
+ if (!$(check).prop("disabled")) {
+ check.checked = false;
+ }
+ });
+ });
+
+ student_toolbar.find(".btn-mark-att")
+ .html(__('Mark Attendance'))
+ .removeClass("btn-default")
+ .on("click", function() {
+ $(me.wrapper.find(".btn-mark-att")).attr("disabled", true);
+ var studs = [];
+ $(me.wrapper.find('input[type="checkbox"]')).each(function(i, check) {
+ var $check = $(check);
+ studs.push({
+ student: $check.data().student,
+ student_name: $check.data().studentName,
+ group_roll_number: $check.data().group_roll_number,
+ disabled: $check.prop("disabled"),
+ checked: $check.is(":checked")
+ });
+ });
+
+ var students_present = studs.filter(function(stud) {
+ return !stud.disabled && stud.checked;
+ });
+
+ var students_absent = studs.filter(function(stud) {
+ return !stud.disabled && !stud.checked;
+ });
+
+ xhiveframework.confirm(__("Do you want to update attendance?
Present: {0}
Absent: {1}",
+ [students_present.length, students_absent.length]),
+ function() { //ifyes
+ if(!xhiveframework.request.ajax_count) {
+ xhiveframework.call({
+ method: "education.education.api.mark_attendance",
+ freeze: true,
+ freeze_message: __("Marking attendance"),
+ args: {
+ "students_present": students_present,
+ "students_absent": students_absent,
+ "student_group": frm.doc.student_group,
+ "course_schedule": frm.doc.course_schedule,
+ "date": frm.doc.date
+ },
+ callback: function(r) {
+ $(me.wrapper.find(".btn-mark-att")).attr("disabled", false);
+ frm.trigger("student_group");
+ }
+ });
+ }
+ },
+ function() { //ifno
+ $(me.wrapper.find(".btn-mark-att")).attr("disabled", false);
+ }
+ );
+ });
+
+ // make html grid of students
+ let student_html = '';
+ for (let student of students) {
+ student_html += `
+
+
+
+
`;
+ }
+
+ $(`
${student_html}
`).appendTo(me.wrapper);
+ }
+
+ show_empty_state() {
+ $(this.wrapper).html(
+ `
+ ${__("No Students in")} ${this.frm.doc.student_group}
+
`
+ );
+ }
+};
diff --git a/education/education/doctype/student_attendance_tool/student_attendance_tool.json b/education/education/doctype/student_attendance_tool/student_attendance_tool.json
new file mode 100644
index 0000000..a9ba746
--- /dev/null
+++ b/education/education/doctype/student_attendance_tool/student_attendance_tool.json
@@ -0,0 +1,118 @@
+{
+ "actions": [],
+ "allow_copy": 1,
+ "creation": "2016-11-16 17:12:46.437539",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "based_on",
+ "group_based_on",
+ "column_break_2",
+ "student_group",
+ "academic_year",
+ "academic_term",
+ "course_schedule",
+ "date",
+ "attendance",
+ "students_html"
+ ],
+ "fields": [
+ {
+ "fieldname": "based_on",
+ "fieldtype": "Select",
+ "label": "Based On",
+ "options": "Student Group\nCourse Schedule"
+ },
+ {
+ "default": "Batch",
+ "depends_on": "eval:doc.based_on == \"Student Group\"",
+ "fieldname": "group_based_on",
+ "fieldtype": "Select",
+ "label": "Group Based On",
+ "options": "Batch\nCourse\nActivity"
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval:doc.based_on ==\"Student Group\"",
+ "fieldname": "student_group",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Student Group",
+ "options": "Student Group",
+ "reqd": 1
+ },
+ {
+ "depends_on": "eval:doc.based_on ==\"Course Schedule\"",
+ "fieldname": "course_schedule",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Course Schedule",
+ "options": "Course Schedule",
+ "reqd": 1
+ },
+ {
+ "depends_on": "eval:doc.based_on ==\"Student Group\"",
+ "fieldname": "date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Date",
+ "reqd": 1
+ },
+ {
+ "depends_on": "eval: (doc.course_schedule \n|| (doc.student_group && doc.date))",
+ "fieldname": "attendance",
+ "fieldtype": "Section Break",
+ "label": "Attendance"
+ },
+ {
+ "fieldname": "students_html",
+ "fieldtype": "HTML",
+ "label": "Students HTML"
+ },
+ {
+ "fetch_from": "student_group.academic_year",
+ "fieldname": "academic_year",
+ "fieldtype": "Link",
+ "label": "Academic Year",
+ "options": "Academic Year",
+ "read_only": 1
+ },
+ {
+ "fetch_from": "student_group.academic_term",
+ "fieldname": "academic_term",
+ "fieldtype": "Link",
+ "label": "Academic Term",
+ "options": "Academic Term",
+ "read_only": 1
+ }
+ ],
+ "hide_toolbar": 1,
+ "issingle": 1,
+ "links": [],
+ "modified": "2020-10-23 17:52:28.078971",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Attendance Tool",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "read": 1,
+ "role": "Instructor",
+ "write": 1
+ },
+ {
+ "create": 1,
+ "read": 1,
+ "role": "Academics User",
+ "write": 1
+ }
+ ],
+ "restrict_to_domain": "",
+ "sort_field": "modified",
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/education/education/doctype/student_attendance_tool/student_attendance_tool.py b/education/education/doctype/student_attendance_tool/student_attendance_tool.py
new file mode 100644
index 0000000..351b768
--- /dev/null
+++ b/education/education/doctype/student_attendance_tool/student_attendance_tool.py
@@ -0,0 +1,67 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+import xhiveframework
+from xhiveframework.model.document import Document
+
+
+class StudentAttendanceTool(Document):
+ pass
+
+
+@xhiveframework.whitelist()
+def get_student_attendance_records(
+ based_on, date=None, student_group=None, course_schedule=None
+):
+ student_list = []
+ student_attendance_list = []
+
+ if based_on == "Course Schedule":
+ student_group = xhiveframework.db.get_value(
+ "Course Schedule", course_schedule, "student_group"
+ )
+ if student_group:
+ student_list = xhiveframework.get_all(
+ "Student Group Student",
+ fields=["student", "student_name", "group_roll_number"],
+ filters={"parent": student_group, "active": 1},
+ order_by="group_roll_number",
+ )
+
+ if not student_list:
+ student_list = xhiveframework.get_all(
+ "Student Group Student",
+ fields=["student", "student_name", "group_roll_number"],
+ filters={"parent": student_group, "active": 1},
+ order_by="group_roll_number",
+ )
+
+ StudentAttendance = xhiveframework.qb.DocType("Student Attendance")
+
+ if course_schedule:
+ student_attendance_list = (
+ xhiveframework.qb.from_(StudentAttendance)
+ .select(StudentAttendance.student, StudentAttendance.status)
+ .where((StudentAttendance.course_schedule == course_schedule))
+ ).run(as_dict=True)
+ else:
+ student_attendance_list = (
+ xhiveframework.qb.from_(StudentAttendance)
+ .select(StudentAttendance.student, StudentAttendance.status)
+ .where(
+ (StudentAttendance.student_group == student_group)
+ & (StudentAttendance.date == date)
+ & (
+ (StudentAttendance.course_schedule == "")
+ | (StudentAttendance.course_schedule.isnull())
+ )
+ )
+ ).run(as_dict=True)
+
+ for attendance in student_attendance_list:
+ for student in student_list:
+ if student.student == attendance.student:
+ student.status = attendance.status
+
+ return student_list
diff --git a/education/education/doctype/student_attendance_tool/test_student_attendance_tool.py b/education/education/doctype/student_attendance_tool/test_student_attendance_tool.py
new file mode 100644
index 0000000..be8c105
--- /dev/null
+++ b/education/education/doctype/student_attendance_tool/test_student_attendance_tool.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2015, Xhive
+# See license.txt
+
+import unittest
+
+
+class TestStudentAttendanceTool(unittest.TestCase):
+ pass
diff --git a/education/education/doctype/student_batch_name/__init__.py b/education/education/doctype/student_batch_name/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/student_batch_name/student_batch_name.js b/education/education/doctype/student_batch_name/student_batch_name.js
new file mode 100644
index 0000000..938a6bc
--- /dev/null
+++ b/education/education/doctype/student_batch_name/student_batch_name.js
@@ -0,0 +1,8 @@
+# Copyright (c) 2015, Xhive
+// For license information, please see license.txt
+
+xhiveframework.ui.form.on('Student Batch Name', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/education/education/doctype/student_batch_name/student_batch_name.json b/education/education/doctype/student_batch_name/student_batch_name.json
new file mode 100644
index 0000000..531c13f
--- /dev/null
+++ b/education/education/doctype/student_batch_name/student_batch_name.json
@@ -0,0 +1,94 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "field:batch_name",
+ "beta": 0,
+ "creation": "2016-11-17 18:45:57.965091",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "batch_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Batch Name",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-11-10 19:08:17.980349",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Batch Name",
+ "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,
+ "restrict_to_domain": "",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 0,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/education/education/doctype/student_batch_name/student_batch_name.py b/education/education/doctype/student_batch_name/student_batch_name.py
new file mode 100644
index 0000000..2401240
--- /dev/null
+++ b/education/education/doctype/student_batch_name/student_batch_name.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+from xhiveframework.model.document import Document
+
+
+class StudentBatchName(Document):
+ pass
diff --git a/education/education/doctype/student_batch_name/test_records.json b/education/education/doctype/student_batch_name/test_records.json
new file mode 100644
index 0000000..bf365c6
--- /dev/null
+++ b/education/education/doctype/student_batch_name/test_records.json
@@ -0,0 +1,8 @@
+[
+ {
+ "batch_name": "_Batch 1"
+ },
+ {
+ "batch_name": "_Batch 2"
+ }
+]
\ No newline at end of file
diff --git a/education/education/doctype/student_batch_name/test_student_batch_name.py b/education/education/doctype/student_batch_name/test_student_batch_name.py
new file mode 100644
index 0000000..8fadfc6
--- /dev/null
+++ b/education/education/doctype/student_batch_name/test_student_batch_name.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2015, Xhive
+# See license.txt
+
+import unittest
+
+# test_records = xhiveframework.get_test_records('Student Batch Name')
+
+
+class TestStudentBatchName(unittest.TestCase):
+ pass
diff --git a/education/education/doctype/student_category/__init__.py b/education/education/doctype/student_category/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/student_category/student_category.js b/education/education/doctype/student_category/student_category.js
new file mode 100644
index 0000000..c6f621d
--- /dev/null
+++ b/education/education/doctype/student_category/student_category.js
@@ -0,0 +1,8 @@
+# Copyright (c) 2015, Xhive
+// For license information, please see license.txt
+
+xhiveframework.ui.form.on('Student Category', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/education/education/doctype/student_category/student_category.json b/education/education/doctype/student_category/student_category.json
new file mode 100644
index 0000000..e6bfc87
--- /dev/null
+++ b/education/education/doctype/student_category/student_category.json
@@ -0,0 +1,93 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 1,
+ "autoname": "field:category",
+ "beta": 0,
+ "creation": "2016-09-05 06:28:33.679415",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "category",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Category",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2020-09-29 10:58:45.783401",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Category",
+ "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,
+ "restrict_to_domain": "",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 0,
+ "track_seen": 0
+}
diff --git a/education/education/doctype/student_category/student_category.py b/education/education/doctype/student_category/student_category.py
new file mode 100644
index 0000000..e124fb4
--- /dev/null
+++ b/education/education/doctype/student_category/student_category.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+from xhiveframework.model.document import Document
+
+
+class StudentCategory(Document):
+ pass
diff --git a/education/education/doctype/student_category/student_category_dashboard.py b/education/education/doctype/student_category/student_category_dashboard.py
new file mode 100644
index 0000000..7f53104
--- /dev/null
+++ b/education/education/doctype/student_category/student_category_dashboard.py
@@ -0,0 +1,10 @@
+from xhiveframework import _
+
+
+def get_data():
+ return {
+ "fieldname": "student_category",
+ "transactions": [
+ {"label": _("Fee"), "items": ["Fee Structure", "Fee Schedule", "Fees"]}
+ ],
+ }
diff --git a/education/education/doctype/student_category/test_student_category.py b/education/education/doctype/student_category/test_student_category.py
new file mode 100644
index 0000000..337400c
--- /dev/null
+++ b/education/education/doctype/student_category/test_student_category.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2015, Xhive
+# See license.txt
+
+import unittest
+
+# test_records = xhiveframework.get_test_records('Student Category')
+
+
+class TestStudentCategory(unittest.TestCase):
+ pass
diff --git a/education/education/doctype/student_group/__init__.py b/education/education/doctype/student_group/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/student_group/student_group.js b/education/education/doctype/student_group/student_group.js
new file mode 100644
index 0000000..0d23105
--- /dev/null
+++ b/education/education/doctype/student_group/student_group.js
@@ -0,0 +1,143 @@
+xhiveframework.ui.form.on('Student Group', {
+ onload: function(frm) {
+ frm.set_query('academic_term', function() {
+ return {
+ filters: {
+ 'academic_year': (frm.doc.academic_year)
+ }
+ };
+ });
+ if (!frm.__islocal) {
+ frm.set_query('student', 'students', function() {
+ return{
+ query: 'education.education.doctype.student_group.student_group.fetch_students',
+ filters: {
+ 'academic_year': frm.doc.academic_year,
+ 'group_based_on': frm.doc.group_based_on,
+ 'academic_term': frm.doc.academic_term,
+ 'program': frm.doc.program,
+ 'batch': frm.doc.batch,
+ 'student_category': frm.doc.student_category,
+ 'course': frm.doc.course,
+ 'student_group': frm.doc.name
+ }
+ }
+ });
+ }
+ },
+
+ refresh: function(frm) {
+ if (!frm.doc.__islocal) {
+
+ frm.add_custom_button(__('Add Guardians to Email Group'), function() {
+ xhiveframework.call({
+ method: 'education.education.api.update_email_group',
+ args: {
+ 'doctype': 'Student Group',
+ 'name': frm.doc.name
+ }
+ });
+ }, __('Actions'));
+
+ frm.add_custom_button(__('Student Attendance Tool'), function() {
+ xhiveframework.route_options = {
+ based_on: 'Student Group',
+ student_group: frm.doc.name
+ }
+ xhiveframework.set_route('Form', 'Student Attendance Tool', 'Student Attendance Tool');
+ }, __('Tools'));
+
+ frm.add_custom_button(__('Course Scheduling Tool'), function() {
+ xhiveframework.route_options = {
+ student_group: frm.doc.name
+ }
+ xhiveframework.set_route('Form', 'Course Scheduling Tool', 'Course Scheduling Tool');
+ }, __('Tools'));
+
+ frm.add_custom_button(__('Newsletter'), function() {
+ xhiveframework.route_options = {
+ 'Newsletter Email Group.email_group': frm.doc.name
+ }
+ xhiveframework.set_route('List', 'Newsletter');
+ }, __('View'));
+
+ }
+ },
+
+ group_based_on: function(frm) {
+ if (frm.doc.group_based_on == 'Batch') {
+ frm.doc.course = null;
+ frm.set_df_property('program', 'reqd', 1);
+ frm.set_df_property('course', 'reqd', 0);
+ }
+ else if (frm.doc.group_based_on == 'Course') {
+ frm.set_df_property('program', 'reqd', 0);
+ frm.set_df_property('course', 'reqd', 1);
+ }
+ else if (frm.doc.group_based_on == 'Activity') {
+ frm.set_df_property('program', 'reqd', 0);
+ frm.set_df_property('course', 'reqd', 0);
+ }
+ },
+
+ get_students: function(frm) {
+ if (frm.doc.group_based_on == 'Batch' || frm.doc.group_based_on == 'Course') {
+ var student_list = [];
+ var max_roll_no = 0;
+ $.each(frm.doc.students, function(_i,d) {
+ student_list.push(d.student);
+ if (d.group_roll_number>max_roll_no) {
+ max_roll_no = d.group_roll_number;
+ }
+ });
+
+ if (frm.doc.academic_year) {
+ xhiveframework.call({
+ method: 'education.education.doctype.student_group.student_group.get_students',
+ args: {
+ 'academic_year': frm.doc.academic_year,
+ 'academic_term': frm.doc.academic_term,
+ 'group_based_on': frm.doc.group_based_on,
+ 'program': frm.doc.program,
+ 'batch' : frm.doc.batch,
+ 'student_category' : frm.doc.student_category,
+ 'course': frm.doc.course
+ },
+ callback: function(r) {
+ if (r.message) {
+ $.each(r.message, function(i, d) {
+ if(!in_list(student_list, d.student)) {
+ var s = frm.add_child('students');
+ s.student = d.student;
+ s.student_name = d.student_name;
+ if (d.active === 0) {
+ s.active = 0;
+ }
+ s.group_roll_number = ++max_roll_no;
+ }
+ });
+ refresh_field('students');
+ frm.save();
+ } else {
+ xhiveframework.msgprint(__('Student Group is already updated.'))
+ }
+ }
+ })
+ }
+ } else {
+ xhiveframework.msgprint(__('Select students manually for the Activity based Group'));
+ }
+ }
+});
+
+xhiveframework.ui.form.on('Student Group Instructor', {
+ instructors_add: function(frm){
+ frm.fields_dict['instructors'].grid.get_field('instructor').get_query = function(doc){
+ let instructor_list = [];
+ $.each(doc.instructors, function(idx, val){
+ instructor_list.push(val.instructor);
+ });
+ return { filters: [['Instructor', 'name', 'not in', instructor_list]] };
+ };
+ }
+});
diff --git a/education/education/doctype/student_group/student_group.json b/education/education/doctype/student_group/student_group.json
new file mode 100644
index 0000000..5562ab7
--- /dev/null
+++ b/education/education/doctype/student_group/student_group.json
@@ -0,0 +1,165 @@
+{
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:student_group_name",
+ "creation": "2015-09-07 12:55:52.072792",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "engine": "InnoDB",
+ "field_order": [
+ "academic_year",
+ "group_based_on",
+ "student_group_name",
+ "max_strength",
+ "column_break_3",
+ "academic_term",
+ "program",
+ "batch",
+ "student_category",
+ "course",
+ "disabled",
+ "section_break_6",
+ "get_students",
+ "students",
+ "section_break_12",
+ "instructors"
+ ],
+ "fields": [
+ {
+ "fieldname": "academic_year",
+ "fieldtype": "Link",
+ "in_standard_filter": 1,
+ "label": "Academic Year",
+ "options": "Academic Year",
+ "reqd": 1
+ },
+ {
+ "fieldname": "group_based_on",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Group Based on",
+ "options": "\nBatch\nCourse\nActivity",
+ "reqd": 1
+ },
+ {
+ "fieldname": "student_group_name",
+ "fieldtype": "Data",
+ "label": "Student Group Name",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "description": "Set 0 for no limit",
+ "fieldname": "max_strength",
+ "fieldtype": "Int",
+ "label": "Max Strength"
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "academic_term",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Academic Term",
+ "options": "Academic Term"
+ },
+ {
+ "fieldname": "program",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "label": "Program",
+ "options": "Program"
+ },
+ {
+ "fieldname": "batch",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "label": "Batch",
+ "options": "Student Batch Name"
+ },
+ {
+ "depends_on": "eval:doc.group_based_on == 'Course'",
+ "fieldname": "course",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "in_standard_filter": 1,
+ "label": "Course",
+ "options": "Course"
+ },
+ {
+ "default": "0",
+ "fieldname": "disabled",
+ "fieldtype": "Check",
+ "label": "Disabled"
+ },
+ {
+ "depends_on": "eval:!doc.__islocal",
+ "fieldname": "section_break_6",
+ "fieldtype": "Section Break",
+ "label": "Students"
+ },
+ {
+ "fieldname": "get_students",
+ "fieldtype": "Button",
+ "label": "Get Students"
+ },
+ {
+ "allow_on_submit": 1,
+ "fieldname": "students",
+ "fieldtype": "Table",
+ "label": "Students",
+ "options": "Student Group Student"
+ },
+ {
+ "fieldname": "section_break_12",
+ "fieldtype": "Section Break",
+ "label": "Instructors"
+ },
+ {
+ "fieldname": "instructors",
+ "fieldtype": "Table",
+ "label": "Instructors",
+ "options": "Student Group Instructor"
+ },
+ {
+ "fieldname": "student_category",
+ "fieldtype": "Link",
+ "label": "Student Category",
+ "options": "Student Category"
+ }
+ ],
+ "links": [],
+ "modified": "2022-12-05 10:50:08.798494",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Group",
+ "naming_rule": "By fieldname",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "read": 1,
+ "role": "Instructor"
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Academics User",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "restrict_to_domain": "",
+ "search_fields": "program, batch, course",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/education/education/doctype/student_group/student_group.py b/education/education/doctype/student_group/student_group.py
new file mode 100644
index 0000000..4187b44
--- /dev/null
+++ b/education/education/doctype/student_group/student_group.py
@@ -0,0 +1,214 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+import xhiveframework
+from xhiveframework import _
+from xhiveframework.model.document import Document
+from xhiveframework.utils import cint
+
+from education.education.utils import validate_duplicate_student
+
+
+class StudentGroup(Document):
+ def validate(self):
+ self.validate_mandatory_fields()
+ self.validate_strength()
+ self.validate_students()
+ self.validate_and_set_child_table_fields()
+ validate_duplicate_student(self.students)
+
+ def validate_mandatory_fields(self):
+ if self.group_based_on == "Course" and not self.course:
+ xhiveframework.throw(_("Please select Course"))
+ if self.group_based_on == "Course" and (not self.program and self.batch):
+ xhiveframework.throw(_("Please select Program"))
+ if self.group_based_on == "Batch" and not self.program:
+ xhiveframework.throw(_("Please select Program"))
+
+ def validate_strength(self):
+ if cint(self.max_strength) < 0:
+ xhiveframework.throw(_("""Max strength cannot be less than zero."""))
+ if self.max_strength and len(self.students) > self.max_strength:
+ xhiveframework.throw(
+ _("""Cannot enroll more than {0} students for this student group.""").format(
+ self.max_strength
+ )
+ )
+
+ def validate_students(self):
+ program_enrollment = get_program_enrollment(
+ self.academic_year,
+ self.academic_term,
+ self.program,
+ self.batch,
+ self.student_category,
+ self.course,
+ )
+ students = [d.student for d in program_enrollment] if program_enrollment else []
+ for d in self.students:
+ if (
+ not xhiveframework.db.get_value("Student", d.student, "enabled")
+ and d.active
+ and not self.disabled
+ ):
+ xhiveframework.throw(
+ _("{0} - {1} is inactive student").format(d.group_roll_number, d.student_name)
+ )
+
+ if (
+ (self.group_based_on == "Batch")
+ and cint(xhiveframework.defaults.get_defaults().validate_batch)
+ and d.student not in students
+ ):
+ xhiveframework.throw(
+ _("{0} - {1} is not enrolled in the Batch {2}").format(
+ d.group_roll_number, d.student_name, self.batch
+ )
+ )
+
+ if (
+ (self.group_based_on == "Course")
+ and cint(xhiveframework.defaults.get_defaults().validate_course)
+ and (d.student not in students)
+ ):
+ xhiveframework.throw(
+ _("{0} - {1} is not enrolled in the Course {2}").format(
+ d.group_roll_number, d.student_name, self.course
+ )
+ )
+
+ def validate_and_set_child_table_fields(self):
+ roll_numbers = [d.group_roll_number for d in self.students if d.group_roll_number]
+ max_roll_no = max(roll_numbers) if roll_numbers else 0
+ roll_no_list = []
+ for d in self.students:
+ if not d.student_name:
+ d.student_name = xhiveframework.db.get_value("Student", d.student, "title")
+ if not d.group_roll_number:
+ max_roll_no += 1
+ d.group_roll_number = max_roll_no
+ if d.group_roll_number in roll_no_list:
+ xhiveframework.throw(_("Duplicate roll number for student {0}").format(d.student_name))
+ else:
+ roll_no_list.append(d.group_roll_number)
+
+
+@xhiveframework.whitelist()
+def get_students(
+ academic_year,
+ group_based_on,
+ academic_term=None,
+ program=None,
+ batch=None,
+ student_category=None,
+ course=None,
+):
+ enrolled_students = get_program_enrollment(
+ academic_year, academic_term, program, batch, student_category, course
+ )
+
+ if enrolled_students:
+ student_list = []
+ for s in enrolled_students:
+ if xhiveframework.db.get_value("Student", s.student, "enabled"):
+ s.update({"active": 1})
+ else:
+ s.update({"active": 0})
+ student_list.append(s)
+ return student_list
+ else:
+ xhiveframework.msgprint(_("No students found"))
+ return []
+
+
+def get_program_enrollment(
+ academic_year,
+ academic_term=None,
+ program=None,
+ batch=None,
+ student_category=None,
+ course=None,
+):
+
+ condition1 = " "
+ condition2 = " "
+ if academic_term:
+ condition1 += " and pe.academic_term = %(academic_term)s"
+ if program:
+ condition1 += " and pe.program = %(program)s"
+ if batch:
+ condition1 += " and pe.student_batch_name = %(batch)s"
+ if student_category:
+ condition1 += " and pe.student_category = %(student_category)s"
+ if course:
+ condition1 += " and pe.name = pec.parent and pec.course = %(course)s"
+ condition2 = ", `tabProgram Enrollment Course` pec"
+
+ return xhiveframework.db.sql(
+ """
+ select
+ pe.student, pe.student_name
+ from
+ `tabProgram Enrollment` pe {condition2}
+ where
+ pe.academic_year = %(academic_year)s
+ and pe.docstatus = 1 {condition1}
+ order by
+ pe.student_name asc
+ """.format(
+ condition1=condition1, condition2=condition2
+ ),
+ (
+ {
+ "academic_year": academic_year,
+ "academic_term": academic_term,
+ "program": program,
+ "batch": batch,
+ "student_category": student_category,
+ "course": course,
+ }
+ ),
+ as_dict=1,
+ )
+
+
+@xhiveframework.whitelist()
+@xhiveframework.validate_and_sanitize_search_inputs
+def fetch_students(doctype, txt, searchfield, start, page_len, filters):
+ if filters.get("group_based_on") != "Activity":
+ enrolled_students = get_program_enrollment(
+ filters.get("academic_year"),
+ filters.get("academic_term"),
+ filters.get("program"),
+ filters.get("batch"),
+ filters.get("student_category"),
+ )
+ student_group_student = xhiveframework.db.sql_list(
+ """select student from `tabStudent Group Student` where parent=%s""",
+ (filters.get("student_group")),
+ )
+ students = (
+ [d.student for d in enrolled_students if d.student not in student_group_student]
+ if enrolled_students
+ else [""]
+ ) or [""]
+ return xhiveframework.db.sql(
+ """select name, student_name from tabStudent
+ where name in ({0}) and (`{1}` LIKE %s or student_name LIKE %s)
+ order by idx desc, name
+ limit %s, %s""".format(
+ ", ".join(["%s"] * len(students)), searchfield
+ ),
+ tuple(students + ["%%%s%%" % txt, "%%%s%%" % txt, start, page_len]),
+ )
+ else:
+ return xhiveframework.db.sql(
+ """select name, student_name from tabStudent
+ where `{0}` LIKE %s or title LIKE %s
+ order by idx desc, name
+ limit %s, %s""".format(
+ searchfield
+ ),
+ tuple(["%%%s%%" % txt, "%%%s%%" % txt, start, page_len]),
+ )
diff --git a/education/education/doctype/student_group/student_group_dashboard.py b/education/education/doctype/student_group/student_group_dashboard.py
new file mode 100644
index 0000000..f2b9668
--- /dev/null
+++ b/education/education/doctype/student_group/student_group_dashboard.py
@@ -0,0 +1,14 @@
+# Copyright (c) 2015, Xhive
+# License: GNU General Public License v3. See license.txt
+
+from xhiveframework import _
+
+
+def get_data():
+ return {
+ "fieldname": "student_group",
+ "transactions": [
+ {"label": _("Assessment"), "items": ["Assessment Plan", "Assessment Result"]},
+ {"label": _("Course"), "items": ["Course Schedule"]},
+ ],
+ }
diff --git a/education/education/doctype/student_group/test_records.json b/education/education/doctype/student_group/test_records.json
new file mode 100644
index 0000000..4c4e042
--- /dev/null
+++ b/education/education/doctype/student_group/test_records.json
@@ -0,0 +1,34 @@
+[
+ {
+ "student_group_name": "Batch-_TP1-_Batch 1-2014-2015 (_Test Academic Term)",
+ "group_based_on": "Batch",
+ "program": "_TP1",
+ "batch": "_Batch 1",
+ "academic_year": "2014-2015",
+ "academic_term": "2014-2015 (_Test Academic Term)",
+ "max_strength": 0
+ },
+ {
+ "student_group_name": "Course-TC101-2014-2015 (_Test Academic Term)",
+ "group_based_on": "Course",
+ "course": "TC101",
+ "academic_year": "2014-2015",
+ "academic_term": "2014-2015 (_Test Academic Term)",
+ "max_strength": 0
+ },
+ {
+ "student_group_name": "Course-TC102-2014-2015 (_Test Academic Term)",
+ "group_based_on": "Course",
+ "course": "TC102",
+ "academic_year": "2014-2015",
+ "academic_term": "2014-2015 (_Test Academic Term)",
+ "max_strength": 0
+ },
+ {
+ "student_group_name": "Activity-2014-2015 (_Test Academic Term)",
+ "group_based_on": "Activity",
+ "academic_year": "2014-2015",
+ "academic_term": "2014-2015 (_Test Academic Term)",
+ "max_strength": 0
+ }
+]
\ No newline at end of file
diff --git a/education/education/doctype/student_group/test_student_group.py b/education/education/doctype/student_group/test_student_group.py
new file mode 100644
index 0000000..c17b7ed
--- /dev/null
+++ b/education/education/doctype/student_group/test_student_group.py
@@ -0,0 +1,52 @@
+# Copyright (c) 2015, Xhive
+# See license.txt
+
+import unittest
+
+import xhiveframework
+
+import education.education
+
+
+def get_random_group():
+ doc = xhiveframework.get_doc(
+ {
+ "doctype": "Student Group",
+ "student_group_name": "_Test Student Group-" + xhiveframework.generate_hash(length=5),
+ "group_based_on": "Activity",
+ }
+ ).insert()
+
+ student_list = xhiveframework.get_all("Student", limit=5)
+
+ doc.extend("students", [{"student": d.name, "active": 1} for d in student_list])
+ doc.save()
+
+ return doc
+
+
+class TestStudentGroup(unittest.TestCase):
+ def test_student_roll_no(self):
+ doc = get_random_group()
+ self.assertEqual(max([d.group_roll_number for d in doc.students]), len(doc.students))
+
+ def test_in_group(self):
+ doc = get_random_group()
+
+ last_student = doc.students[-1].student
+
+ # remove last student
+ doc.students = doc.students[:-1]
+ doc.save()
+
+ self.assertRaises(
+ education.education.StudentNotInGroupError,
+ education.education.validate_student_belongs_to_group,
+ last_student,
+ doc.name,
+ )
+
+ # safe, don't throw validation
+ education.education.validate_student_belongs_to_group(
+ doc.students[0].student, doc.name
+ )
diff --git a/education/education/doctype/student_group_creation_tool/__init__.py b/education/education/doctype/student_group_creation_tool/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/student_group_creation_tool/student_group_creation_tool.js b/education/education/doctype/student_group_creation_tool/student_group_creation_tool.js
new file mode 100644
index 0000000..7c311e1
--- /dev/null
+++ b/education/education/doctype/student_group_creation_tool/student_group_creation_tool.js
@@ -0,0 +1,40 @@
+xhiveframework.ui.form.on("Student Group Creation Tool", "refresh", function(frm) {
+ frm.disable_save();
+ frm.page.set_primary_action(__("Create Student Groups"), function() {
+ xhiveframework.call({
+ method: "create_student_groups",
+ doc:frm.doc
+ })
+ });
+ xhiveframework.realtime.on("student_group_creation_progress", function(data) {
+ if(data.progress) {
+ xhiveframework.hide_msgprint(true);
+ xhiveframework.show_progress(__("Creating student groups"), data.progress[0],data.progress[1]);
+ }
+ });
+});
+
+xhiveframework.ui.form.on("Student Group Creation Tool", "get_courses", function(frm) {
+ frm.set_value("courses",[]);
+ if (frm.doc.academic_year && frm.doc.program) {
+ xhiveframework.call({
+ method: "get_courses",
+ doc:frm.doc,
+ callback: function(r) {
+ if(r.message) {
+ frm.set_value("courses", r.message);
+ }
+ }
+ })
+ }
+});
+
+xhiveframework.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)
+ }
+ };
+ });
+});
diff --git a/education/education/doctype/student_group_creation_tool/student_group_creation_tool.json b/education/education/doctype/student_group_creation_tool/student_group_creation_tool.json
new file mode 100644
index 0000000..c751a9d
--- /dev/null
+++ b/education/education/doctype/student_group_creation_tool/student_group_creation_tool.json
@@ -0,0 +1,309 @@
+{
+ "allow_copy": 1,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2016-01-04 14:45:36.576933",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 0,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "academic_year",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 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,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "description": "Leave blank if you make students groups per year",
+ "fieldname": "academic_term",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Academic Term",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Academic Term",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "get_courses",
+ "fieldtype": "Button",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Get Courses",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "description": "",
+ "fieldname": "program",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Program",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Program",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "description": "Leave unchecked if you don't want to consider batch while making course based groups. ",
+ "fieldname": "separate_groups",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Separate course based Group for every Batch",
+ "length": 0,
+ "no_copy": 0,
+ "options": "",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "courses",
+ "fieldtype": "Table",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Courses",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Student Group Creation Tool Course",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 1,
+ "hide_toolbar": 1,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 1,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-12-27 09:35:30.211254",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Group Creation Tool",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 0,
+ "email": 0,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 0,
+ "read": 1,
+ "report": 0,
+ "role": "Education Manager",
+ "set_user_permissions": 0,
+ "share": 0,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "restrict_to_domain": "",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/education/education/doctype/student_group_creation_tool/student_group_creation_tool.py b/education/education/doctype/student_group_creation_tool/student_group_creation_tool.py
new file mode 100644
index 0000000..99227dd
--- /dev/null
+++ b/education/education/doctype/student_group_creation_tool/student_group_creation_tool.py
@@ -0,0 +1,111 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+import xhiveframework
+from xhiveframework import _
+from xhiveframework.model.document import Document
+
+from education.education.doctype.student_group.student_group import \
+ get_students
+
+
+class StudentGroupCreationTool(Document):
+ @xhiveframework.whitelist()
+ def get_courses(self):
+ group_list = []
+
+ batches = xhiveframework.db.sql(
+ """select name as batch from `tabStudent Batch Name`""", as_dict=1
+ )
+ for batch in batches:
+ group_list.append({"group_based_on": "Batch", "batch": batch.batch})
+
+ courses = xhiveframework.db.sql(
+ """select course, course_name from `tabProgram Course` where parent=%s""",
+ (self.program),
+ as_dict=1,
+ )
+ if self.separate_groups:
+ from itertools import product
+
+ course_list = product(courses, batches)
+ for course in course_list:
+ temp_dict = {}
+ temp_dict.update({"group_based_on": "Course"})
+ temp_dict.update(course[0])
+ temp_dict.update(course[1])
+ group_list.append(temp_dict)
+ else:
+ for course in courses:
+ course.update({"group_based_on": "Course"})
+ group_list.append(course)
+
+ for group in group_list:
+ if group.get("group_based_on") == "Batch":
+ student_group_name = (
+ self.program
+ + "/"
+ + group.get("batch")
+ + "/"
+ + (self.academic_term if self.academic_term else self.academic_year)
+ )
+ group.update({"student_group_name": student_group_name})
+ elif group.get("group_based_on") == "Course":
+ student_group_name = (
+ group.get("course")
+ + "/"
+ + self.program
+ + ("/" + group.get("batch") if group.get("batch") else "")
+ + "/"
+ + (self.academic_term if self.academic_term else self.academic_year)
+ )
+ group.update({"student_group_name": student_group_name})
+
+ return group_list
+
+ @xhiveframework.whitelist()
+ def create_student_groups(self):
+ if not self.courses:
+ xhiveframework.throw(_("""No Student Groups created."""))
+
+ l = len(self.courses)
+ for d in self.courses:
+ if not d.student_group_name:
+ xhiveframework.throw(_("Student Group Name is mandatory in row {0}").format(d.idx))
+
+ if d.group_based_on == "Course" and not d.course:
+ xhiveframework.throw(_("Course is mandatory in row {0}").format(d.idx))
+
+ if d.group_based_on == "Batch" and not d.batch:
+ xhiveframework.throw(_("Batch is mandatory in row {0}").format(d.idx))
+
+ xhiveframework.publish_realtime(
+ "student_group_creation_progress",
+ {"progress": [d.idx, l]},
+ user=xhiveframework.session.user,
+ )
+
+ student_group = xhiveframework.new_doc("Student Group")
+ student_group.student_group_name = d.student_group_name
+ student_group.group_based_on = d.group_based_on
+ student_group.program = self.program
+ student_group.course = d.course
+ student_group.batch = d.batch
+ student_group.max_strength = d.max_strength
+ student_group.academic_term = self.academic_term
+ student_group.academic_year = self.academic_year
+ student_list = get_students(
+ self.academic_year,
+ d.group_based_on,
+ self.academic_term,
+ self.program,
+ d.batch,
+ d.course,
+ )
+
+ for student in student_list:
+ student_group.append("students", student)
+ student_group.save()
+
+ xhiveframework.msgprint(_("{0} Student Groups created.").format(l))
diff --git a/education/education/doctype/student_group_creation_tool/test_student_group_creation_tool.py b/education/education/doctype/student_group_creation_tool/test_student_group_creation_tool.py
new file mode 100644
index 0000000..9ab56bc
--- /dev/null
+++ b/education/education/doctype/student_group_creation_tool/test_student_group_creation_tool.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2015, Xhive
+# See license.txt
+
+import unittest
+
+
+class TestStudentGroupCreationTool(unittest.TestCase):
+ pass
diff --git a/education/education/doctype/student_group_creation_tool_course/__init__.py b/education/education/doctype/student_group_creation_tool_course/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.json b/education/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.json
new file mode 100644
index 0000000..3f1eb8a
--- /dev/null
+++ b/education/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.json
@@ -0,0 +1,272 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2016-01-04 15:03:57.940079",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "group_based_on",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Group Based On",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nBatch\nCourse",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "course",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Course",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Course",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "batch",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Batch",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Student Batch Name",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "student_group_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Student Group Name",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "course.course_name",
+ "fieldname": "course_code",
+ "fieldtype": "Read Only",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Course Code",
+ "length": 0,
+ "no_copy": 0,
+ "options": "",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "max_strength",
+ "fieldtype": "Int",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Max Strength",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2018-11-04 03:38:52.525155",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Group Creation Tool Course",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "restrict_to_domain": "",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/education/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.py b/education/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.py
new file mode 100644
index 0000000..43b914d
--- /dev/null
+++ b/education/education/doctype/student_group_creation_tool_course/student_group_creation_tool_course.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+from xhiveframework.model.document import Document
+
+
+class StudentGroupCreationToolCourse(Document):
+ pass
diff --git a/education/education/doctype/student_group_instructor/__init__.py b/education/education/doctype/student_group_instructor/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/student_group_instructor/student_group_instructor.json b/education/education/doctype/student_group_instructor/student_group_instructor.json
new file mode 100644
index 0000000..8547e75
--- /dev/null
+++ b/education/education/doctype/student_group_instructor/student_group_instructor.json
@@ -0,0 +1,142 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2017-04-17 16:06:01.406768",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "instructor",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Instructor",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Instructor",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "instructor.instructor_name",
+ "fieldname": "instructor_name",
+ "fieldtype": "Read Only",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Instructor Name",
+ "length": 0,
+ "no_copy": 0,
+ "options": "",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2018-11-04 03:39:02.413082",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Group Instructor",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "restrict_to_domain": "",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 0,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/education/education/doctype/student_group_instructor/student_group_instructor.py b/education/education/doctype/student_group_instructor/student_group_instructor.py
new file mode 100644
index 0000000..d70b449
--- /dev/null
+++ b/education/education/doctype/student_group_instructor/student_group_instructor.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+from xhiveframework.model.document import Document
+
+
+class StudentGroupInstructor(Document):
+ pass
diff --git a/education/education/doctype/student_group_student/__init__.py b/education/education/doctype/student_group_student/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/student_group_student/student_group_student.json b/education/education/doctype/student_group_student/student_group_student.json
new file mode 100644
index 0000000..6f3c6d0
--- /dev/null
+++ b/education/education/doctype/student_group_student/student_group_student.json
@@ -0,0 +1,60 @@
+{
+ "actions": [],
+ "creation": "2015-09-11 15:14:58.501830",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "student",
+ "student_name",
+ "column_break_2",
+ "group_roll_number",
+ "active"
+ ],
+ "fields": [
+ {
+ "fieldname": "student",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Student",
+ "options": "Student",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "student.student_name",
+ "fieldname": "student_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Student Name",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "group_roll_number",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "Group Roll Number"
+ },
+ {
+ "default": "1",
+ "fieldname": "active",
+ "fieldtype": "Check",
+ "in_list_view": 1,
+ "label": "Active"
+ }
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2023-02-07 16:22:46.912057",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Group Student",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/education/education/doctype/student_group_student/student_group_student.py b/education/education/doctype/student_group_student/student_group_student.py
new file mode 100644
index 0000000..9c559f4
--- /dev/null
+++ b/education/education/doctype/student_group_student/student_group_student.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+from xhiveframework.model.document import Document
+
+
+class StudentGroupStudent(Document):
+ pass
diff --git a/education/education/doctype/student_guardian/__init__.py b/education/education/doctype/student_guardian/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/student_guardian/student_guardian.json b/education/education/doctype/student_guardian/student_guardian.json
new file mode 100644
index 0000000..3e34f77
--- /dev/null
+++ b/education/education/doctype/student_guardian/student_guardian.json
@@ -0,0 +1,51 @@
+{
+ "actions": [],
+ "creation": "2016-09-01 14:28:39.174471",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "guardian",
+ "guardian_name",
+ "relation"
+ ],
+ "fields": [
+ {
+ "fieldname": "guardian",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Guardian",
+ "options": "Guardian",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "guardian.guardian_name",
+ "fieldname": "guardian_name",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "label": "Guardian Name",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "relation",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Relation",
+ "options": "\nMother\nFather\nOthers"
+ }
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2023-02-14 17:05:21.300964",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Guardian",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/education/education/doctype/student_guardian/student_guardian.py b/education/education/doctype/student_guardian/student_guardian.py
new file mode 100644
index 0000000..fc316bf
--- /dev/null
+++ b/education/education/doctype/student_guardian/student_guardian.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+from xhiveframework.model.document import Document
+
+
+class StudentGuardian(Document):
+ pass
diff --git a/education/education/doctype/student_language/__init__.py b/education/education/doctype/student_language/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/student_language/student_language.js b/education/education/doctype/student_language/student_language.js
new file mode 100644
index 0000000..da7aa45
--- /dev/null
+++ b/education/education/doctype/student_language/student_language.js
@@ -0,0 +1,8 @@
+# Copyright (c) 2015, Xhive
+// For license information, please see license.txt
+
+xhiveframework.ui.form.on('Student Language', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/education/education/doctype/student_language/student_language.json b/education/education/doctype/student_language/student_language.json
new file mode 100644
index 0000000..c46c1e1
--- /dev/null
+++ b/education/education/doctype/student_language/student_language.json
@@ -0,0 +1,98 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "field:language_name",
+ "beta": 0,
+ "creation": "2017-02-21 01:55:00.366273",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "language_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Language Name",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 1
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-11-04 03:37:34.712397",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Language",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 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,
+ "restrict_to_domain": "",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "",
+ "track_changes": 1,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/education/education/doctype/student_language/student_language.py b/education/education/doctype/student_language/student_language.py
new file mode 100644
index 0000000..b1749c0
--- /dev/null
+++ b/education/education/doctype/student_language/student_language.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+from xhiveframework.model.document import Document
+
+
+class StudentLanguage(Document):
+ pass
diff --git a/education/education/doctype/student_language/test_student_language.py b/education/education/doctype/student_language/test_student_language.py
new file mode 100644
index 0000000..63f7bf1
--- /dev/null
+++ b/education/education/doctype/student_language/test_student_language.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2015, Xhive
+# See license.txt
+
+import unittest
+
+# test_records = xhiveframework.get_test_records('Student Language')
+
+
+class TestStudentLanguage(unittest.TestCase):
+ pass
diff --git a/education/education/doctype/student_leave_application/__init__.py b/education/education/doctype/student_leave_application/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/student_leave_application/student_leave_application.js b/education/education/doctype/student_leave_application/student_leave_application.js
new file mode 100644
index 0000000..253416b
--- /dev/null
+++ b/education/education/doctype/student_leave_application/student_leave_application.js
@@ -0,0 +1,32 @@
+# Copyright (c) 2015, Xhive
+// For license information, please see license.txt
+
+xhiveframework.ui.form.on('Student Leave Application', {
+ "student": function(frm) {
+ xhiveframework.call({
+ method: "education.education.doctype.student_leave_application.student_leave_application.get_student_groups",
+ args: {
+ student: frm.doc.student
+ },
+ callback: function(r) {
+ if (r.message) {
+ frm.set_query("student_group", ()=>{
+ return {
+ filters :{
+ 'name': ['in', r.message]
+ }
+ }
+ })
+ frm.set_query("course_schedule", ()=>{
+ return {
+ filters :{
+ 'student_group': ['in', r.message]
+ }
+ }
+ })
+ };
+ }
+ });
+
+ },
+});
\ No newline at end of file
diff --git a/education/education/doctype/student_leave_application/student_leave_application.json b/education/education/doctype/student_leave_application/student_leave_application.json
new file mode 100644
index 0000000..97b6f13
--- /dev/null
+++ b/education/education/doctype/student_leave_application/student_leave_application.json
@@ -0,0 +1,165 @@
+{
+ "actions": [],
+ "autoname": "EDU-SLA-.YYYY.-.#####",
+ "creation": "2016-11-28 15:38:54.793854",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "student",
+ "student_name",
+ "column_break_3",
+ "from_date",
+ "to_date",
+ "total_leave_days",
+ "section_break_5",
+ "attendance_based_on",
+ "student_group",
+ "course_schedule",
+ "mark_as_present",
+ "column_break_11",
+ "reason",
+ "amended_from"
+ ],
+ "fields": [
+ {
+ "fieldname": "student",
+ "fieldtype": "Link",
+ "in_global_search": 1,
+ "label": "Student",
+ "options": "Student",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "student.student_name",
+ "fieldname": "student_name",
+ "fieldtype": "Read Only",
+ "in_global_search": 1,
+ "label": "Student Name",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "from_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "From Date",
+ "reqd": 1
+ },
+ {
+ "fieldname": "to_date",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "To Date",
+ "reqd": 1
+ },
+ {
+ "default": "0",
+ "description": "Check this to mark the student as present in case the student is not attending the institute to participate or represent the institute in any event.\n\n",
+ "fieldname": "mark_as_present",
+ "fieldtype": "Check",
+ "label": "Mark as Present"
+ },
+ {
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "reason",
+ "fieldtype": "Text",
+ "label": "Reason"
+ },
+ {
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "label": "Amended From",
+ "no_copy": 1,
+ "options": "Student Leave Application",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
+ "allow_in_quick_entry": 1,
+ "default": "Student Group",
+ "fieldname": "attendance_based_on",
+ "fieldtype": "Select",
+ "label": "Attendance Based On",
+ "options": "Student Group\nCourse Schedule"
+ },
+ {
+ "allow_in_quick_entry": 1,
+ "depends_on": "eval:doc.attendance_based_on === \"Student Group\";",
+ "fieldname": "student_group",
+ "fieldtype": "Link",
+ "label": "Student Group",
+ "mandatory_depends_on": "eval:doc.attendance_based_on === \"Student Group\";",
+ "options": "Student Group"
+ },
+ {
+ "allow_in_quick_entry": 1,
+ "depends_on": "eval:doc.attendance_based_on === \"Course Schedule\";",
+ "fieldname": "course_schedule",
+ "fieldtype": "Link",
+ "label": "Course Schedule",
+ "mandatory_depends_on": "eval:doc.attendance_based_on === \"Course Schedule\";",
+ "options": "Course Schedule"
+ },
+ {
+ "fieldname": "column_break_11",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "total_leave_days",
+ "fieldtype": "Float",
+ "label": "Total Leave Days",
+ "read_only": 1
+ }
+ ],
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2020-09-21 18:10:24.440660",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Leave Application",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Instructor",
+ "submit": 1,
+ "write": 1
+ },
+ {
+ "amend": 1,
+ "cancel": 1,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Academics User",
+ "share": 1,
+ "submit": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "restrict_to_domain": "",
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "student_name"
+}
\ No newline at end of file
diff --git a/education/education/doctype/student_leave_application/student_leave_application.py b/education/education/doctype/student_leave_application/student_leave_application.py
new file mode 100644
index 0000000..66a05c0
--- /dev/null
+++ b/education/education/doctype/student_leave_application/student_leave_application.py
@@ -0,0 +1,151 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+from datetime import timedelta
+
+import xhiveframework
+from xhiveerp.setup.doctype.holiday_list.holiday_list import is_holiday
+from xhiveframework import _
+from xhiveframework.model.document import Document
+from xhiveframework.utils import date_diff, flt, get_link_to_form, getdate
+
+from education.education.doctype.student_attendance.student_attendance import (
+ get_holiday_list,
+)
+
+
+class StudentLeaveApplication(Document):
+ def validate(self):
+ self.validate_holiday_list()
+ self.validate_duplicate()
+ self.validate_from_to_dates("from_date", "to_date")
+
+ def on_submit(self):
+ self.update_attendance()
+
+ def on_cancel(self):
+ self.cancel_attendance()
+
+ def validate_duplicate(self):
+ data = xhiveframework.db.sql(
+ """select name from `tabStudent Leave Application`
+ where
+ ((%(from_date)s > from_date and %(from_date)s < to_date) or
+ (%(to_date)s > from_date and %(to_date)s < to_date) or
+ (%(from_date)s <= from_date and %(to_date)s >= to_date)) and
+ name != %(name)s and student = %(student)s and docstatus < 2
+ """,
+ {
+ "from_date": self.from_date,
+ "to_date": self.to_date,
+ "student": self.student,
+ "name": self.name,
+ },
+ as_dict=1,
+ )
+
+ if data:
+ link = get_link_to_form("Student Leave Application", data[0].name)
+ xhiveframework.throw(
+ _("Leave application {0} already exists against the student {1}").format(
+ link, xhiveframework.bold(self.student)
+ ),
+ title=_("Duplicate Entry"),
+ )
+
+ def validate_holiday_list(self):
+ holiday_list = get_holiday_list()
+ self.total_leave_days = get_number_of_leave_days(
+ self.from_date, self.to_date, holiday_list
+ )
+
+ def update_attendance(self):
+ holiday_list = get_holiday_list()
+
+ for dt in daterange(getdate(self.from_date), getdate(self.to_date)):
+ date = dt.strftime("%Y-%m-%d")
+
+ if is_holiday(holiday_list, date):
+ continue
+
+ attendance = xhiveframework.db.exists(
+ "Student Attendance",
+ {"student": self.student, "date": date, "docstatus": ("!=", 2)},
+ )
+
+ status = "Present" if self.mark_as_present else "Absent"
+ if attendance:
+ # update existing attendance record
+ values = dict()
+ values["status"] = status
+ values["leave_application"] = self.name
+ xhiveframework.db.set_value("Student Attendance", attendance, values)
+ else:
+ # make a new attendance record
+ doc = xhiveframework.new_doc("Student Attendance")
+ doc.student = self.student
+ doc.student_name = self.student_name
+ doc.date = date
+ doc.leave_application = self.name
+ doc.status = status
+ if self.attendance_based_on == "Student Group":
+ doc.student_group = self.student_group
+ else:
+ doc.course_schedule = self.course_schedule
+ doc.insert(ignore_permissions=True, ignore_mandatory=True)
+ doc.submit()
+
+ def cancel_attendance(self):
+ if self.docstatus == 2:
+ attendance = xhiveframework.db.sql(
+ """
+ SELECT name
+ FROM `tabStudent Attendance`
+ WHERE
+ student = %s and
+ (date between %s and %s) and
+ docstatus < 2
+ """,
+ (self.student, self.from_date, self.to_date),
+ as_dict=1,
+ )
+
+ for name in attendance:
+ xhiveframework.db.set_value("Student Attendance", name, "docstatus", 2)
+
+
+def daterange(start_date, end_date):
+ for n in range(int((end_date - start_date).days) + 1):
+ yield start_date + timedelta(n)
+
+
+def get_number_of_leave_days(from_date, to_date, holiday_list):
+ number_of_days = date_diff(to_date, from_date) + 1
+
+ holidays = xhiveframework.db.sql(
+ """
+ SELECT
+ COUNT(DISTINCT holiday_date)
+ FROM `tabHoliday` h1,`tabHoliday List` h2
+ WHERE
+ h1.parent = h2.name and
+ h1.holiday_date between %s and %s and
+ h2.name = %s""",
+ (from_date, to_date, holiday_list),
+ )[0][0]
+
+ number_of_days = flt(number_of_days) - flt(holidays)
+
+ return number_of_days
+
+
+@xhiveframework.whitelist()
+def get_student_groups(student):
+ student_group = xhiveframework.db.get_list(
+ "Student Group Student",
+ pluck="parent",
+ filters={"student": student},
+ )
+
+ return student_group
diff --git a/education/education/doctype/student_leave_application/student_leave_application_dashboard.py b/education/education/doctype/student_leave_application/student_leave_application_dashboard.py
new file mode 100644
index 0000000..6e4d180
--- /dev/null
+++ b/education/education/doctype/student_leave_application/student_leave_application_dashboard.py
@@ -0,0 +1,5 @@
+def get_data():
+ return {
+ "fieldname": "leave_application",
+ "transactions": [{"items": ["Student Attendance"]}],
+ }
diff --git a/education/education/doctype/student_leave_application/test_student_leave_application.py b/education/education/doctype/student_leave_application/test_student_leave_application.py
new file mode 100644
index 0000000..95357ce
--- /dev/null
+++ b/education/education/doctype/student_leave_application/test_student_leave_application.py
@@ -0,0 +1,139 @@
+# Copyright (c) 2015, Xhive
+# See license.txt
+
+import unittest
+
+import xhiveframework
+from xhiveerp import get_default_company
+from xhiveframework.utils import add_days, add_months, getdate
+
+from education.education.doctype.student.test_student import create_student
+from education.education.doctype.student_group.test_student_group import \
+ get_random_group
+
+
+class TestStudentLeaveApplication(unittest.TestCase):
+ def setUp(self):
+ xhiveframework.db.sql("""delete from `tabStudent Leave Application`""")
+ create_holiday_list()
+
+ def test_attendance_record_creation(self):
+ leave_application = create_leave_application()
+ attendance_record = xhiveframework.db.exists(
+ "Student Attendance",
+ {"leave_application": leave_application.name, "status": "Absent"},
+ )
+ self.assertTrue(attendance_record)
+
+ # mark as present
+ date = add_days(getdate(), -1)
+ leave_application = create_leave_application(date, date, 1)
+ attendance_record = xhiveframework.db.exists(
+ "Student Attendance",
+ {"leave_application": leave_application.name, "status": "Present"},
+ )
+ self.assertTrue(attendance_record)
+
+ def test_attendance_record_updated(self):
+ attendance = create_student_attendance()
+ create_leave_application()
+ self.assertEqual(
+ xhiveframework.db.get_value("Student Attendance", attendance.name, "status"), "Absent"
+ )
+
+ def test_attendance_record_cancellation(self):
+ leave_application = create_leave_application()
+ leave_application.cancel()
+ attendance_status = xhiveframework.db.get_value(
+ "Student Attendance", {"leave_application": leave_application.name}, "docstatus"
+ )
+ self.assertTrue(attendance_status, 2)
+
+ def test_holiday(self):
+ today = getdate()
+ leave_application = create_leave_application(
+ from_date=today, to_date=add_days(today, 1), submit=0
+ )
+
+ # holiday list validation
+ company = get_default_company() or xhiveframework.get_all("Company")[0].name
+ xhiveframework.db.set_value("Company", company, "default_holiday_list", "")
+ self.assertRaises(xhiveframework.ValidationError, leave_application.save)
+
+ xhiveframework.db.set_value(
+ "Company", company, "default_holiday_list", "Test Holiday List for Student"
+ )
+ leave_application.save()
+
+ leave_application.reload()
+ self.assertEqual(leave_application.total_leave_days, 1)
+
+ # check no attendance record created for a holiday
+ leave_application.submit()
+ self.assertIsNone(
+ xhiveframework.db.exists(
+ "Student Attendance",
+ {"leave_application": leave_application.name, "date": add_days(today, 1)},
+ )
+ )
+
+ def tearDown(self):
+ company = get_default_company() or xhiveframework.get_all("Company")[0].name
+ xhiveframework.db.set_value("Company", company, "default_holiday_list", "_Test Holiday List")
+
+
+def create_leave_application(from_date=None, to_date=None, mark_as_present=0, submit=1):
+ student = get_student()
+
+ leave_application = xhiveframework.new_doc("Student Leave Application")
+ leave_application.student = student.name
+ leave_application.attendance_based_on = "Student Group"
+ leave_application.student_group = get_random_group().name
+ leave_application.from_date = from_date if from_date else getdate()
+ leave_application.to_date = from_date if from_date else getdate()
+ leave_application.mark_as_present = mark_as_present
+
+ if submit:
+ leave_application.insert()
+ leave_application.submit()
+
+ return leave_application
+
+
+def create_student_attendance(date=None, status=None):
+ student = get_student()
+ attendance = xhiveframework.get_doc(
+ {
+ "doctype": "Student Attendance",
+ "student": student.name,
+ "status": status if status else "Present",
+ "date": date if date else getdate(),
+ "student_group": get_random_group().name,
+ }
+ ).insert()
+ return attendance
+
+
+def get_student():
+ return create_student(
+ dict(email="test_student@gmail.com", first_name="Test", last_name="Student")
+ )
+
+
+def create_holiday_list():
+ holiday_list = "Test Holiday List for Student"
+ today = getdate()
+ if not xhiveframework.db.exists("Holiday List", holiday_list):
+ xhiveframework.get_doc(
+ dict(
+ doctype="Holiday List",
+ holiday_list_name=holiday_list,
+ from_date=add_months(today, -6),
+ to_date=add_months(today, 6),
+ holidays=[dict(holiday_date=add_days(today, 1), description="Test")],
+ )
+ ).insert()
+
+ company = get_default_company() or xhiveframework.get_all("Company")[0].name
+ xhiveframework.db.set_value("Company", company, "default_holiday_list", holiday_list)
+ return holiday_list
diff --git a/education/education/doctype/student_log/__init__.py b/education/education/doctype/student_log/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/student_log/student_log.js b/education/education/doctype/student_log/student_log.js
new file mode 100644
index 0000000..8b112cd
--- /dev/null
+++ b/education/education/doctype/student_log/student_log.js
@@ -0,0 +1,8 @@
+# Copyright (c) 2015, Xhive
+// For license information, please see license.txt
+
+xhiveframework.ui.form.on('Student Log', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/education/education/doctype/student_log/student_log.json b/education/education/doctype/student_log/student_log.json
new file mode 100644
index 0000000..c0e7a12
--- /dev/null
+++ b/education/education/doctype/student_log/student_log.json
@@ -0,0 +1,423 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "autoname": "EDU-SLOG-.YYYY.-.#####",
+ "beta": 0,
+ "creation": "2016-07-29 03:27:22.451772",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "student",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 1,
+ "label": "Student",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Student",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fetch_from": "student.student_name",
+ "fieldname": "student_name",
+ "fieldtype": "Read Only",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 1,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Student Name",
+ "length": 0,
+ "no_copy": 0,
+ "options": "",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "type",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 1,
+ "label": "Type",
+ "length": 0,
+ "no_copy": 0,
+ "options": "General\nAcademic\nMedical\nAchievement",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Date",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "academic_year",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 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,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "academic_term",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Academic Term",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Academic Term",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "program",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Program",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Program",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "student_batch",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Student Batch",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Student Batch Name",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "log",
+ "fieldtype": "Text Editor",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 1,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Log",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2018-08-21 16:15:47.027649",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Log",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 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": 0,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "restrict_to_domain": "",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "student_name",
+ "track_changes": 0,
+ "track_seen": 1,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/education/education/doctype/student_log/student_log.py b/education/education/doctype/student_log/student_log.py
new file mode 100644
index 0000000..001a90c
--- /dev/null
+++ b/education/education/doctype/student_log/student_log.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+from xhiveframework.model.document import Document
+
+
+class StudentLog(Document):
+ pass
diff --git a/education/education/doctype/student_log/test_student_log.py b/education/education/doctype/student_log/test_student_log.py
new file mode 100644
index 0000000..0fb3e49
--- /dev/null
+++ b/education/education/doctype/student_log/test_student_log.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2015, Xhive
+# See license.txt
+
+import unittest
+
+# test_records = xhiveframework.get_test_records('Student Log')
+
+
+class TestStudentLog(unittest.TestCase):
+ pass
diff --git a/education/education/doctype/student_report_generation_tool/__init__.py b/education/education/doctype/student_report_generation_tool/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/student_report_generation_tool/student_report_generation_tool.html b/education/education/doctype/student_report_generation_tool/student_report_generation_tool.html
new file mode 100644
index 0000000..39629f5
--- /dev/null
+++ b/education/education/doctype/student_report_generation_tool/student_report_generation_tool.html
@@ -0,0 +1,359 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ doc.students[0] }}
+
+
+
+
+
+
+
+
+ {{ doc.student_name }}
+
+
+
+
+
+
+
+
+ {{ doc.program }}
+
+
+
+ {% if doc.student_batch %}
+
+
+
+
+
+ {{ doc.student_batch }}
+
+
+ {% endif %}
+
+
+
+
+
+
+
+
+ {{ doc.academic_year }}
+
+
+
+ {% if doc.academic_term %}
+
+
+
+
+
+ {{ doc.academic_term }}
+
+
+ {% endif %}
+
+
+
+
+
+
+ {{ doc.assessment_group }}
+
+
+
+
+
+
+ {% for course in courses %}
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ xhiveframework.db.get_value("Course", course, "course_name") }}
+
+
+
+
+
+ {{ _("Term") }} |
+ {{ _("Assessment Criteria") }} |
+ {% if doc.show_marks %}
+ {{ _("Score") }} |
+ {% endif %}
+ {{ _("Grade") }} |
+
+
+
+
+ {% for result in assessment_result %}
+ {% for criteria in result.details %}
+ {% if result.course == course %}
+
+ {{ result.assessment_group }} |
+ {{ criteria.assessment_criteria }} |
+ {% if doc.show_marks %}
+ {{ criteria.score }} |
+ {% endif %}
+ {{ criteria.grade }} |
+
+ {% endif %}
+ {% endfor %}
+ {% endfor %}
+
+
+
+
+
+
+
+ {% endfor %}
+
+
+
+
+
+
{{ _("Student Attendance")}}
+
+ {{ _("Present ") }} {{ doc.attendance.present if doc.attendance.present else 0 }} {{ _(" out of ") }} {{ doc.attendance.total }} {{ _(" days") }}
+
+
+
+
+
{{ _("Parents Teacher Meeting Attendance")}}
+
+ {{ _("Present ") }} {{ doc.parents_attendance if doc.parents_attendance != None else 0 }}
+ {{ _(" out of ") }} {{ doc.parents_meeting if doc.parents_meeting != None else 0 }} {{ _(" meetings") }}
+
+
+
+
+
+
+ {% if doc.assessment_terms %}
+
+
+
{{ _("Terms") }}
+
{{ doc.assessment_terms }}
+
+
+ {% endif %}
+
diff --git a/education/education/doctype/student_report_generation_tool/student_report_generation_tool.js b/education/education/doctype/student_report_generation_tool/student_report_generation_tool.js
new file mode 100644
index 0000000..919119d
--- /dev/null
+++ b/education/education/doctype/student_report_generation_tool/student_report_generation_tool.js
@@ -0,0 +1,55 @@
+# Copyright (c) 2015, Xhive
+// For license information, please see license.txt
+
+xhiveframework.ui.form.on('Student Report Generation Tool', {
+ onload: function(frm) {
+ frm.set_query("academic_term",function(){
+ return{
+ "filters":{
+ "academic_year": frm.doc.academic_year
+ }
+ };
+ });
+ frm.set_query("assessment_group", function() {
+ return{
+ filters: {
+ "is_group": 1
+ }
+ };
+ });
+ },
+
+ refresh: function(frm) {
+ frm.disable_save();
+ frm.page.clear_indicator();
+ frm.page.set_primary_action(__('Print Report Card'), () => {
+ let doc = frm.doc;
+ if (!doc.student || !doc.assessment_group || !doc.program || !doc.academic_year) {
+ xhiveframework.throw(__("Please fill in all the mandatory fields."))
+ }
+ let url = "/api/method/education.education.doctype.student_report_generation_tool.student_report_generation_tool.preview_report_card";
+ open_url_post(url, {"doc": frm.doc}, true);
+ });
+ },
+
+ student: function(frm) {
+ if (frm.doc.student) {
+ xhiveframework.call({
+ method:"education.education.api.get_current_enrollment",
+ args: {
+ "student": frm.doc.student,
+ "academic_year": frm.doc.academic_year
+ },
+ callback: function(r) {
+ if(r){
+ $.each(r.message, function(i, d) {
+ if (frm.fields_dict.hasOwnProperty(i)) {
+ frm.set_value(i, d);
+ }
+ });
+ }
+ }
+ });
+ }
+ }
+});
diff --git a/education/education/doctype/student_report_generation_tool/student_report_generation_tool.json b/education/education/doctype/student_report_generation_tool/student_report_generation_tool.json
new file mode 100644
index 0000000..9e18829
--- /dev/null
+++ b/education/education/doctype/student_report_generation_tool/student_report_generation_tool.json
@@ -0,0 +1,153 @@
+{
+ "actions": [],
+ "creation": "2018-01-15 15:36:32.830069",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "student",
+ "student_name",
+ "program",
+ "student_batch",
+ "column_break_3",
+ "assessment_group",
+ "academic_year",
+ "academic_term",
+ "section_break_5",
+ "add_letterhead",
+ "letter_head",
+ "parents_meeting",
+ "parents_attendance",
+ "column_break_15",
+ "show_marks",
+ "terms",
+ "assessment_terms"
+ ],
+ "fields": [
+ {
+ "fieldname": "student",
+ "fieldtype": "Link",
+ "label": "Student",
+ "options": "Student",
+ "reqd": 1
+ },
+ {
+ "fetch_from": "student.student_name",
+ "fieldname": "student_name",
+ "fieldtype": "Read Only",
+ "label": "Student Name"
+ },
+ {
+ "fieldname": "program",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Program",
+ "options": "Program",
+ "reqd": 1
+ },
+ {
+ "fieldname": "student_batch",
+ "fieldtype": "Link",
+ "label": "Batch",
+ "options": "Student Batch Name"
+ },
+ {
+ "default": "0",
+ "fieldname": "show_marks",
+ "fieldtype": "Check",
+ "label": "Show Marks"
+ },
+ {
+ "default": "1",
+ "fieldname": "add_letterhead",
+ "fieldtype": "Check",
+ "label": "Add letterhead"
+ },
+ {
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "assessment_group",
+ "fieldtype": "Link",
+ "label": "Assessment Group",
+ "options": "Assessment Group",
+ "reqd": 1
+ },
+ {
+ "fieldname": "academic_year",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Academic Year",
+ "options": "Academic Year",
+ "reqd": 1
+ },
+ {
+ "fieldname": "academic_term",
+ "fieldtype": "Link",
+ "label": "Academic Term",
+ "options": "Academic Term"
+ },
+ {
+ "depends_on": "add_letterhead",
+ "fieldname": "letter_head",
+ "fieldtype": "Link",
+ "label": "Letter Head",
+ "options": "Letter Head"
+ },
+ {
+ "fieldname": "section_break_5",
+ "fieldtype": "Section Break",
+ "label": "Report Settings"
+ },
+ {
+ "fieldname": "parents_meeting",
+ "fieldtype": "Data",
+ "label": "Total Parents Teacher Meeting"
+ },
+ {
+ "fieldname": "parents_attendance",
+ "fieldtype": "Data",
+ "label": "No. of Meetings Attended by Parents"
+ },
+ {
+ "fieldname": "terms",
+ "fieldtype": "Link",
+ "label": "Terms",
+ "options": "Terms and Conditions"
+ },
+ {
+ "fetch_from": "terms.terms",
+ "fieldname": "assessment_terms",
+ "fieldtype": "Small Text",
+ "label": "Assessment Terms",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_15",
+ "fieldtype": "Column Break"
+ }
+ ],
+ "hide_toolbar": 1,
+ "issingle": 1,
+ "links": [],
+ "modified": "2022-12-07 17:53:40.391739",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Report Generation Tool",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "read": 1,
+ "role": "System Manager",
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "restrict_to_domain": "",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": [],
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/education/education/doctype/student_report_generation_tool/student_report_generation_tool.py b/education/education/doctype/student_report_generation_tool/student_report_generation_tool.py
new file mode 100644
index 0000000..653cc13
--- /dev/null
+++ b/education/education/doctype/student_report_generation_tool/student_report_generation_tool.py
@@ -0,0 +1,85 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+import json
+
+import xhiveframework
+from xhiveframework import _
+from xhiveframework.model.document import Document
+from xhiveframework.utils.pdf import get_pdf
+from xhiveframework.www.printview import get_letter_head
+
+from education.education.report.course_wise_assessment_report.course_wise_assessment_report import (
+ get_child_assessment_groups, get_formatted_result)
+
+
+class StudentReportGenerationTool(Document):
+ pass
+
+
+@xhiveframework.whitelist()
+def preview_report_card(doc):
+ doc = xhiveframework._dict(json.loads(doc))
+ doc.students = [doc.student]
+ values = get_formatted_result(doc, get_course=True)
+ courses = values.get("courses")
+ assessment_groups = get_child_assessment_groups(doc.assessment_group)
+ letterhead = get_letter_head(doc, not doc.add_letterhead)
+
+ # get the attendance of the student for that peroid of time.
+ doc.attendance = get_attendance_count(
+ doc.students[0], doc.academic_year, doc.academic_term
+ )
+
+ html = xhiveframework.render_template(
+ "education/education/doctype/student_report_generation_tool/student_report_generation_tool.html",
+ {
+ "doc": doc,
+ "assessment_result": values.get("assessment_result"),
+ "courses": courses,
+ "assessment_groups": assessment_groups,
+ "letterhead": letterhead and letterhead.get("content", None),
+ "add_letterhead": doc.add_letterhead if doc.add_letterhead else 0,
+ },
+ )
+
+ final_template = xhiveframework.render_template(
+ "xhiveframework/www/printview.html", {"body": html, "title": "Report Card"}
+ )
+
+ xhiveframework.response.filename = "Report Card " + doc.students[0] + ".pdf"
+ xhiveframework.response.filecontent = get_pdf(final_template)
+ xhiveframework.response.type = "pdf"
+
+
+def get_attendance_count(student, academic_year, academic_term=None):
+ attendance = xhiveframework._dict()
+ attendance.total = 0
+
+ if academic_year:
+ from_date, to_date = xhiveframework.db.get_value(
+ "Academic Year", academic_year, ["year_start_date", "year_end_date"]
+ )
+ elif academic_term:
+ from_date, to_date = xhiveframework.db.get_value(
+ "Academic Term", academic_term, ["term_start_date", "term_end_date"]
+ )
+
+ if from_date and to_date:
+ data = xhiveframework.get_all(
+ "Student Attendance",
+ {"student": student, "docstatus": 1, "date": ["between", (from_date, to_date)]},
+ ["status", "count(student) as count"],
+ group_by="status",
+ )
+
+ for row in data:
+ if row.status == "Present":
+ attendance.present = row.count
+ if row.status == "Absent":
+ attendance.absent = row.count
+ attendance.total += row.count
+ return attendance
+ else:
+ xhiveframework.throw(_("Please enter the Academic Year and set the Start and End date."))
diff --git a/education/education/doctype/student_report_generation_tool/test_student_report_generation_tool.py b/education/education/doctype/student_report_generation_tool/test_student_report_generation_tool.py
new file mode 100644
index 0000000..42dd9aa
--- /dev/null
+++ b/education/education/doctype/student_report_generation_tool/test_student_report_generation_tool.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2015, Xhive
+# See license.txt
+
+import unittest
+
+
+class TestStudentReportGenerationTool(unittest.TestCase):
+ pass
diff --git a/education/education/doctype/student_sibling/__init__.py b/education/education/doctype/student_sibling/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/student_sibling/student_sibling.json b/education/education/doctype/student_sibling/student_sibling.json
new file mode 100644
index 0000000..3886684
--- /dev/null
+++ b/education/education/doctype/student_sibling/student_sibling.json
@@ -0,0 +1,84 @@
+{
+ "actions": [],
+ "creation": "2016-09-01 14:41:23.824083",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+ "studying_in_same_institute",
+ "full_name",
+ "gender",
+ "column_break_4",
+ "student",
+ "institution",
+ "program",
+ "date_of_birth"
+ ],
+ "fields": [
+ {
+ "fieldname": "studying_in_same_institute",
+ "fieldtype": "Select",
+ "label": "Studying in Same Institute",
+ "options": "NO\nYES"
+ },
+ {
+ "columns": 3,
+ "fetch_from": "student.student_name",
+ "fieldname": "full_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Full Name"
+ },
+ {
+ "columns": 1,
+ "fieldname": "gender",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Gender",
+ "options": "Gender"
+ },
+ {
+ "fieldname": "column_break_4",
+ "fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "eval:doc.studying_in_same_institute == \"YES\"",
+ "fieldname": "student",
+ "fieldtype": "Link",
+ "label": "Student ID",
+ "options": "Student"
+ },
+ {
+ "columns": 2,
+ "depends_on": "eval:doc.studying_in_same_institute == \"NO\"",
+ "fieldname": "institution",
+ "fieldtype": "Data",
+ "label": "Institution"
+ },
+ {
+ "columns": 2,
+ "fieldname": "program",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Program"
+ },
+ {
+ "columns": 2,
+ "fieldname": "date_of_birth",
+ "fieldtype": "Date",
+ "in_list_view": 1,
+ "label": "Date of Birth"
+ }
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2023-02-14 18:40:12.974746",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Sibling",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/education/education/doctype/student_sibling/student_sibling.py b/education/education/doctype/student_sibling/student_sibling.py
new file mode 100644
index 0000000..07b0415
--- /dev/null
+++ b/education/education/doctype/student_sibling/student_sibling.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+from xhiveframework.model.document import Document
+
+
+class StudentSibling(Document):
+ pass
diff --git a/education/education/doctype/student_siblings/__init__.py b/education/education/doctype/student_siblings/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/student_siblings/student_siblings.json b/education/education/doctype/student_siblings/student_siblings.json
new file mode 100644
index 0000000..0b04a11
--- /dev/null
+++ b/education/education/doctype/student_siblings/student_siblings.json
@@ -0,0 +1,141 @@
+{
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2016-09-01 14:41:23.824083",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "name1",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Name",
+ "length": 0,
+ "no_copy": 0,
+ "options": "",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "gender",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Gender",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nMale\nFemale",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "date_of_birth",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Date of Birth",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2018-11-04 03:37:46.485218",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Siblings",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "restrict_to_domain": "",
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 0,
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/education/education/doctype/student_siblings/student_siblings.py b/education/education/doctype/student_siblings/student_siblings.py
new file mode 100644
index 0000000..ea0c200
--- /dev/null
+++ b/education/education/doctype/student_siblings/student_siblings.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+from xhiveframework.model.document import Document
+
+
+class StudentSiblings(Document):
+ pass
diff --git a/education/education/doctype/topic/__init__.py b/education/education/doctype/topic/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/topic/test_topic.py b/education/education/doctype/topic/test_topic.py
new file mode 100644
index 0000000..776fe8c
--- /dev/null
+++ b/education/education/doctype/topic/test_topic.py
@@ -0,0 +1,59 @@
+# Copyright (c) 2015, Xhive
+# See license.txt
+
+import unittest
+
+import xhiveframework
+
+
+class TestTopic(unittest.TestCase):
+ def setUp(self):
+ make_topic_and_linked_content(
+ "_Test Topic 1", [{"type": "Article", "name": "_Test Article 1"}]
+ )
+
+ def test_get_contents(self):
+ topic = xhiveframework.get_doc("Topic", "_Test Topic 1")
+ contents = topic.get_contents()
+ self.assertEqual(contents[0].doctype, "Article")
+ self.assertEqual(contents[0].name, "_Test Article 1")
+ xhiveframework.db.rollback()
+
+
+def make_topic(name):
+ try:
+ topic = xhiveframework.get_doc("Topic", name)
+ except xhiveframework.DoesNotExistError:
+ topic = xhiveframework.get_doc(
+ {
+ "doctype": "Topic",
+ "topic_name": name,
+ "topic_code": name,
+ }
+ ).insert()
+ return topic.name
+
+
+def make_topic_and_linked_content(topic_name, content_dict_list):
+ try:
+ topic = xhiveframework.get_doc("Topic", topic_name)
+ except xhiveframework.DoesNotExistError:
+ make_topic(topic_name)
+ topic = xhiveframework.get_doc("Topic", topic_name)
+ content_list = [
+ make_content(content["type"], content["name"]) for content in content_dict_list
+ ]
+ for content in content_list:
+ topic.append(
+ "topic_content", {"content": content.title, "content_type": content.doctype}
+ )
+ topic.save()
+ return topic
+
+
+def make_content(type, name):
+ try:
+ content = xhiveframework.get_doc(type, name)
+ except xhiveframework.DoesNotExistError:
+ content = xhiveframework.get_doc({"doctype": type, "title": name}).insert()
+ return content
diff --git a/education/education/doctype/topic/topic.js b/education/education/doctype/topic/topic.js
new file mode 100644
index 0000000..710ba36
--- /dev/null
+++ b/education/education/doctype/topic/topic.js
@@ -0,0 +1,55 @@
+# Copyright (c) 2015, Xhive
+// For license information, please see license.txt
+
+xhiveframework.ui.form.on('Topic', {
+ refresh: function(frm) {
+ if (!cur_frm.doc.__islocal) {
+ frm.add_custom_button(__('Add to Courses'), function() {
+ frm.trigger('add_topic_to_courses');
+ }, __('Action'));
+ }
+ },
+
+ add_topic_to_courses: function(frm) {
+ get_courses_without_topic(frm.doc.name).then(r => {
+ if (r.message.length) {
+ xhiveframework.prompt([
+ {
+ fieldname: 'courses',
+ label: __('Courses'),
+ fieldtype: 'MultiSelectPills',
+ get_data: function() {
+ return r.message;
+ }
+ }
+ ],
+ function(data) {
+ xhiveframework.call({
+ method: 'education.education.doctype.topic.topic.add_topic_to_courses',
+ args: {
+ 'topic': frm.doc.name,
+ 'courses': data.courses
+ },
+ callback: function(r) {
+ if (!r.exc) {
+ frm.reload_doc();
+ }
+ },
+ freeze: true,
+ freeze_message: __('...Adding Topic to Courses')
+ });
+ }, __('Add Topic to Courses'), __('Add'));
+ } else {
+ xhiveframework.msgprint(__('This topic is already added to the existing courses'));
+ }
+ });
+ }
+});
+
+let get_courses_without_topic = function(topic) {
+ return xhiveframework.call({
+ type: 'GET',
+ method: 'education.education.doctype.topic.topic.get_courses_without_topic',
+ args: {'topic': topic}
+ });
+};
diff --git a/education/education/doctype/topic/topic.json b/education/education/doctype/topic/topic.json
new file mode 100644
index 0000000..305458b
--- /dev/null
+++ b/education/education/doctype/topic/topic.json
@@ -0,0 +1,90 @@
+{
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:topic_name",
+ "creation": "2018-12-12 11:37:39.917760",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "topic_name",
+ "topic_content",
+ "description",
+ "hero_image"
+ ],
+ "fields": [
+ {
+ "fieldname": "topic_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Name",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "topic_content",
+ "fieldtype": "Table",
+ "label": "Topic Content",
+ "options": "Topic Content"
+ },
+ {
+ "fieldname": "hero_image",
+ "fieldtype": "Attach Image",
+ "hidden": 1,
+ "label": "Hero Image"
+ },
+ {
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "label": "Description"
+ }
+ ],
+ "image_field": "hero_image",
+ "modified": "2019-06-12 12:34:49.911300",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Topic",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Administrator",
+ "share": 1,
+ "write": 1
+ },
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "Instructor",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/education/education/doctype/topic/topic.py b/education/education/doctype/topic/topic.py
new file mode 100644
index 0000000..1b8a1f7
--- /dev/null
+++ b/education/education/doctype/topic/topic.py
@@ -0,0 +1,76 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+import json
+
+import xhiveframework
+from xhiveframework import _
+from xhiveframework.model.document import Document
+
+
+class Topic(Document):
+ def get_contents(self):
+ try:
+ topic_content_list = self.topic_content
+ content_data = [
+ xhiveframework.get_doc(topic_content.content_type, topic_content.content)
+ for topic_content in topic_content_list
+ ]
+ except Exception as e:
+ xhiveframework.log_error(xhiveframework.get_traceback())
+ return None
+ return content_data
+
+
+@xhiveframework.whitelist()
+def get_courses_without_topic(topic):
+ data = []
+ for entry in xhiveframework.db.get_all("Course"):
+ course = xhiveframework.get_doc("Course", entry.name)
+ topics = [t.topic for t in course.topics]
+ if not topics or topic not in topics:
+ data.append(course.name)
+ return data
+
+
+@xhiveframework.whitelist()
+def add_topic_to_courses(topic, courses, mandatory=False):
+ courses = json.loads(courses)
+ for entry in courses:
+ course = xhiveframework.get_doc("Course", entry)
+ course.append("topics", {"topic": topic, "topic_name": topic})
+ course.flags.ignore_mandatory = True
+ course.save()
+ xhiveframework.db.commit()
+ xhiveframework.msgprint(
+ _("Topic {0} has been added to all the selected courses successfully.").format(
+ xhiveframework.bold(topic)
+ ),
+ title=_("Courses updated"),
+ indicator="green",
+ )
+
+
+@xhiveframework.whitelist()
+def add_content_to_topics(content_type, content, topics):
+ topics = json.loads(topics)
+ for entry in topics:
+ topic = xhiveframework.get_doc("Topic", entry)
+ topic.append(
+ "topic_content",
+ {
+ "content_type": content_type,
+ "content": content,
+ },
+ )
+ topic.flags.ignore_mandatory = True
+ topic.save()
+ xhiveframework.db.commit()
+ xhiveframework.msgprint(
+ _("{0} {1} has been added to all the selected topics successfully.").format(
+ content_type, xhiveframework.bold(content)
+ ),
+ title=_("Topics updated"),
+ indicator="green",
+ )
diff --git a/education/education/doctype/topic_content/__init__.py b/education/education/doctype/topic_content/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/doctype/topic_content/test_topic_content.py b/education/education/doctype/topic_content/test_topic_content.py
new file mode 100644
index 0000000..f165c96
--- /dev/null
+++ b/education/education/doctype/topic_content/test_topic_content.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2015, Xhive
+# See license.txt
+
+import unittest
+
+
+class TestTopicContent(unittest.TestCase):
+ pass
diff --git a/education/education/doctype/topic_content/topic_content.js b/education/education/doctype/topic_content/topic_content.js
new file mode 100644
index 0000000..b750d72
--- /dev/null
+++ b/education/education/doctype/topic_content/topic_content.js
@@ -0,0 +1,8 @@
+# Copyright (c) 2015, Xhive
+// For license information, please see license.txt
+
+xhiveframework.ui.form.on('Topic Content', {
+ refresh: function(frm) {
+
+ }
+});
diff --git a/education/education/doctype/topic_content/topic_content.json b/education/education/doctype/topic_content/topic_content.json
new file mode 100644
index 0000000..444fd1d
--- /dev/null
+++ b/education/education/doctype/topic_content/topic_content.json
@@ -0,0 +1,44 @@
+{
+ "creation": "2018-12-12 11:42:57.987434",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "content_type",
+ "column_break_2",
+ "content"
+ ],
+ "fields": [
+ {
+ "fieldname": "content_type",
+ "fieldtype": "Select",
+ "in_list_view": 1,
+ "label": "Content Type",
+ "options": "\nArticle\nVideo\nQuiz",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "content",
+ "fieldtype": "Dynamic Link",
+ "in_list_view": 1,
+ "label": "Content",
+ "options": "content_type",
+ "reqd": 1
+ }
+ ],
+ "istable": 1,
+ "modified": "2019-05-14 11:12:49.153771",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Topic Content",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/education/education/doctype/topic_content/topic_content.py b/education/education/doctype/topic_content/topic_content.py
new file mode 100644
index 0000000..38674b4
--- /dev/null
+++ b/education/education/doctype/topic_content/topic_content.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+from xhiveframework.model.document import Document
+
+
+class TopicContent(Document):
+ pass
diff --git a/education/education/report/__init__.py b/education/education/report/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/report/absent_student_report/__init__.py b/education/education/report/absent_student_report/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/report/absent_student_report/absent_student_report.js b/education/education/report/absent_student_report/absent_student_report.js
new file mode 100644
index 0000000..bb5e0ab
--- /dev/null
+++ b/education/education/report/absent_student_report/absent_student_report.js
@@ -0,0 +1,15 @@
+# Copyright (c) 2015, Xhive
+// License: GNU General Public License v3. See license.txt
+
+
+xhiveframework.query_reports["Absent Student Report"] = {
+ "filters": [
+ {
+ "fieldname":"date",
+ "label": __("Date"),
+ "fieldtype": "Date",
+ "default": xhiveframework.datetime.get_today(),
+ "reqd": 1
+ }
+ ]
+}
diff --git a/education/education/report/absent_student_report/absent_student_report.json b/education/education/report/absent_student_report/absent_student_report.json
new file mode 100644
index 0000000..92ad860
--- /dev/null
+++ b/education/education/report/absent_student_report/absent_student_report.json
@@ -0,0 +1,24 @@
+{
+ "add_total_row": 0,
+ "creation": "2013-05-13 14:04:03",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 3,
+ "is_standard": "Yes",
+ "modified": "2020-06-24 17:16:40.251116",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Absent Student Report",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Student Attendance",
+ "report_name": "Absent Student Report",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Academics User"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/education/education/report/absent_student_report/absent_student_report.py b/education/education/report/absent_student_report/absent_student_report.py
new file mode 100644
index 0000000..89dc17a
--- /dev/null
+++ b/education/education/report/absent_student_report/absent_student_report.py
@@ -0,0 +1,133 @@
+# Copyright (c) 2015, Xhive
+# License: GNU General Public License v3. See license.txt
+
+
+import xhiveframework
+from xhiveerp.setup.doctype.holiday_list.holiday_list import is_holiday
+from xhiveframework import _, msgprint
+from xhiveframework.utils import formatdate
+
+from education.education.doctype.student_attendance.student_attendance import (
+ get_holiday_list,
+)
+
+
+def execute(filters=None):
+ if not filters:
+ filters = {}
+
+ if not filters.get("date"):
+ msgprint(_("Please select date"), raise_exception=1)
+
+ columns = get_columns(filters)
+ date = filters.get("date")
+
+ holiday_list = get_holiday_list()
+ if is_holiday(holiday_list, filters.get("date")):
+ msgprint(
+ _("No attendance has been marked for {0} as it is a Holiday").format(
+ xhiveframework.bold(formatdate(filters.get("date")))
+ )
+ )
+
+ absent_students = get_absent_students(date)
+ leave_applicants = get_leave_applications(date)
+ if absent_students:
+ student_list = [d["student"] for d in absent_students]
+
+ data = []
+ for student in absent_students:
+ if not student.student in leave_applicants:
+ row = [student.student, student.student_name, student.student_group]
+ stud_details = xhiveframework.db.get_value(
+ "Student",
+ student.student,
+ ["student_email_id", "student_mobile_number"],
+ as_dict=True,
+ )
+
+ if stud_details.student_email_id:
+ row += [stud_details.student_email_id]
+ else:
+ row += [""]
+
+ if stud_details.student_mobile_number:
+ row += [stud_details.student_mobile_number]
+ else:
+ row += [""]
+
+ data.append(row)
+
+ return columns, data
+
+
+def get_columns(filters):
+ columns = [
+ _("Student") + ":Link/Student:90",
+ _("Student Name") + "::150",
+ _("Student Group") + "::180",
+ _("Student Email Address") + "::180",
+ _("Student Mobile No.") + "::150",
+ ]
+ return columns
+
+
+def get_absent_students(date):
+ absent_students = xhiveframework.db.sql(
+ """
+ SELECT student, student_name, student_group
+ FROM `tabStudent Attendance`
+ WHERE
+ status='Absent' and docstatus=1 and date = %s
+ ORDER BY
+ student_group, student_name""",
+ date,
+ as_dict=1,
+ )
+ return absent_students
+
+
+def get_leave_applications(date):
+ leave_applicants = []
+ leave_applications = xhiveframework.db.sql(
+ """
+ SELECT student
+ FROM
+ `tabStudent Leave Application`
+ WHERE
+ docstatus = 1 and mark_as_present = 1 and
+ from_date <= %s and to_date >= %s
+ """,
+ (date, date),
+ )
+ for student in leave_applications:
+ leave_applicants.append(student[0])
+
+ return leave_applicants
+
+
+def get_transportation_details(date, student_list):
+ academic_year = xhiveframework.get_all(
+ "Academic Year",
+ filters=[["year_start_date", "<=", date], ["year_end_date", ">=", date]],
+ )
+ if academic_year:
+ academic_year = academic_year[0].name
+ elif xhiveframework.defaults.get_defaults().academic_year:
+ academic_year = xhiveframework.defaults.get_defaults().academic_year
+ else:
+ return {}
+
+ transportation_details = xhiveframework.get_all(
+ "Program Enrollment",
+ fields=["student", "mode_of_transportation", "vehicle_no"],
+ filters={
+ "student": ("in", student_list),
+ "academic_year": academic_year,
+ "docstatus": ("not in", ["2"]),
+ },
+ )
+ transportation_map = {}
+ for d in transportation_details:
+ transportation_map[d.student] = [d.mode_of_transportation, d.vehicle_no]
+ return transportation_map
diff --git a/education/education/report/assessment_plan_status/__init__.py b/education/education/report/assessment_plan_status/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/report/assessment_plan_status/assessment_plan_status.js b/education/education/report/assessment_plan_status/assessment_plan_status.js
new file mode 100644
index 0000000..07b55a8
--- /dev/null
+++ b/education/education/report/assessment_plan_status/assessment_plan_status.js
@@ -0,0 +1,28 @@
+# Copyright (c) 2015, Xhive
+// For license information, please see license.txt
+/* eslint-disable */
+
+xhiveframework.query_reports["Assessment Plan Status"] = {
+ "filters": [
+ {
+ "fieldname":"assessment_group",
+ "label": __("Assessment Group"),
+ "fieldtype": "Link",
+ "options": "Assessment Group",
+ "get_query": function() {
+ return{
+ filters: {
+ 'is_group': 0
+ }
+ };
+ }
+ },
+ {
+ "fieldname":"schedule_date",
+ "label": __("Scheduled Upto"),
+ "fieldtype": "Date",
+ "options": ""
+ }
+
+ ]
+}
diff --git a/education/education/report/assessment_plan_status/assessment_plan_status.json b/education/education/report/assessment_plan_status/assessment_plan_status.json
new file mode 100644
index 0000000..cbca648
--- /dev/null
+++ b/education/education/report/assessment_plan_status/assessment_plan_status.json
@@ -0,0 +1,24 @@
+{
+ "add_total_row": 0,
+ "creation": "2017-11-09 15:07:30.404428",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2020-06-24 17:16:02.027410",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Assessment Plan Status",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Assessment Plan",
+ "report_name": "Assessment Plan Status",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Academics User"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/education/education/report/assessment_plan_status/assessment_plan_status.py b/education/education/report/assessment_plan_status/assessment_plan_status.py
new file mode 100644
index 0000000..bf6cecc
--- /dev/null
+++ b/education/education/report/assessment_plan_status/assessment_plan_status.py
@@ -0,0 +1,200 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+from itertools import groupby
+
+import xhiveframework
+from xhiveframework import _
+from xhiveframework.utils import cint
+
+DOCSTATUS = {
+ 0: "saved",
+ 1: "submitted",
+}
+
+
+def execute(filters=None):
+ columns, data = [], []
+
+ args = xhiveframework._dict()
+ args["assessment_group"] = filters.get("assessment_group")
+ args["schedule_date"] = filters.get("schedule_date")
+
+ columns = get_column()
+
+ data, chart = get_assessment_data(args)
+
+ return columns, data, None, chart
+
+
+def get_assessment_data(args=None):
+
+ # [total, saved, submitted, remaining]
+ chart_data = [0, 0, 0, 0]
+
+ condition = ""
+ if args["assessment_group"]:
+ condition += "and assessment_group = %(assessment_group)s"
+ if args["schedule_date"]:
+ condition += "and schedule_date <= %(schedule_date)s"
+
+ assessment_plan = xhiveframework.db.sql(
+ """
+ SELECT
+ ap.name as assessment_plan,
+ ap.assessment_name,
+ ap.student_group,
+ ap.schedule_date,
+ (select count(*) from `tabStudent Group Student` sgs where sgs.parent=ap.student_group)
+ as student_group_strength
+ FROM
+ `tabAssessment Plan` ap
+ WHERE
+ ap.docstatus = 1 {condition}
+ ORDER BY
+ ap.modified desc
+ """.format(
+ condition=condition
+ ),
+ (args),
+ as_dict=1,
+ )
+
+ assessment_plan_list = (
+ [d.assessment_plan for d in assessment_plan] if assessment_plan else [""]
+ )
+ assessment_result = get_assessment_result(assessment_plan_list)
+
+ for d in assessment_plan:
+
+ assessment_plan_details = assessment_result.get(d.assessment_plan)
+ assessment_plan_details = (
+ xhiveframework._dict()
+ if not assessment_plan_details
+ else xhiveframework._dict(assessment_plan_details)
+ )
+ if "saved" not in assessment_plan_details:
+ assessment_plan_details.update({"saved": 0})
+ if "submitted" not in assessment_plan_details:
+ assessment_plan_details.update({"submitted": 0})
+
+ # remaining students whose marks not entered
+ remaining_students = (
+ cint(d.student_group_strength)
+ - cint(assessment_plan_details.saved)
+ - cint(assessment_plan_details.submitted)
+ )
+ assessment_plan_details.update({"remaining": remaining_students})
+ d.update(assessment_plan_details)
+
+ chart_data[0] += cint(d.student_group_strength)
+ chart_data[1] += assessment_plan_details.saved
+ chart_data[2] += assessment_plan_details.submitted
+ chart_data[3] += assessment_plan_details.remaining
+
+ chart = get_chart(chart_data[1:])
+
+ return assessment_plan, chart
+
+
+def get_assessment_result(assessment_plan_list):
+ assessment_result_dict = xhiveframework._dict()
+
+ assessment_result = xhiveframework.db.sql(
+ """
+ SELECT
+ assessment_plan, docstatus, count(*) as count
+ FROM
+ `tabAssessment Result`
+ WHERE
+ assessment_plan in (%s)
+ GROUP BY
+ assessment_plan, docstatus
+ ORDER BY
+ assessment_plan
+ """
+ % ", ".join(["%s"] * len(assessment_plan_list)),
+ tuple(assessment_plan_list),
+ as_dict=1,
+ )
+
+ for key, group in groupby(assessment_result, lambda ap: ap["assessment_plan"]):
+ tmp = {}
+ for d in group:
+ if d.docstatus in [0, 1]:
+ tmp.update({DOCSTATUS[d.docstatus]: d.count})
+ assessment_result_dict[key] = tmp
+
+ return assessment_result_dict
+
+
+def get_chart(chart_data):
+ return {
+ "data": {
+ "labels": ["Saved", "Submitted", "Remaining"],
+ "datasets": [{"values": chart_data}],
+ },
+ "type": "percentage",
+ }
+
+
+def get_column():
+ return [
+ {
+ "fieldname": "assessment_plan",
+ "label": _("Assessment Plan"),
+ "fieldtype": "Link",
+ "options": "Assessment Plan",
+ "width": 120,
+ },
+ {
+ "fieldname": "assessment_name",
+ "label": _("Assessment Plan Name"),
+ "fieldtype": "Data",
+ "options": "",
+ "width": 200,
+ },
+ {
+ "fieldname": "schedule_date",
+ "label": _("Schedule Date"),
+ "fieldtype": "Date",
+ "options": "",
+ "width": 100,
+ },
+ {
+ "fieldname": "student_group",
+ "label": _("Student Group"),
+ "fieldtype": "Link",
+ "options": "Student Group",
+ "width": 200,
+ },
+ {
+ "fieldname": "student_group_strength",
+ "label": _("Total Student"),
+ "fieldtype": "Data",
+ "options": "",
+ "width": 100,
+ },
+ {
+ "fieldname": "submitted",
+ "label": _("Submitted"),
+ "fieldtype": "Data",
+ "options": "",
+ "width": 100,
+ },
+ {
+ "fieldname": "saved",
+ "label": _("Saved"),
+ "fieldtype": "Data",
+ "options": "",
+ "width": 100,
+ },
+ {
+ "fieldname": "remaining",
+ "label": _("Remaining"),
+ "fieldtype": "Data",
+ "options": "",
+ "width": 100,
+ },
+ ]
diff --git a/education/education/report/course_wise_assessment_report/__init__.py b/education/education/report/course_wise_assessment_report/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/report/course_wise_assessment_report/course_wise_assessment_report.html b/education/education/report/course_wise_assessment_report/course_wise_assessment_report.html
new file mode 100644
index 0000000..6a8916e
--- /dev/null
+++ b/education/education/report/course_wise_assessment_report/course_wise_assessment_report.html
@@ -0,0 +1,50 @@
+{%
+ var letterhead = filters.letter_head || (xhiveframework.get_doc(":Company", filters.company) && xhiveframework.get_doc(":Company", filters.company).default_letter_head) || xhiveframework.defaults.get_default("letter_head");
+ var report_columns = report.get_columns_for_print();
+%}
+{% if(letterhead) { %}
+
+ {%= xhiveframework.boot.letter_heads[letterhead].header %}
+
+{% } %}
+
{%= __("Assessment Report") %}
+
+
{%= __("Academic Year: ") %} {%= filters.academic_year %}
+{% if (filters.academic_term){ %}
+
{%= __("Academic Term: ") %} {%= filters.academic_term %}
+{% } %}
+
{%= __("Course Code: ") %} {%= filters.course %}
+
{%= __("Assessment Group: ") %} {%= filters.assessment_group %}
+{% if (filters.student_group){ %}
+
{%= __("Student Group: ") %} {%= filters.student_group %}
+{% } %}
+
+
+
+
+
+ {% for(var i=1, l=report_columns.length; i{%= report_columns[i].label %}
+ {% } %}
+
+
+
+ {% for(var j=0, k=data.length; j
+ {% for(var i=1, l=report_columns.length; i
+ {% var fieldname = report_columns[i].fieldname; %}
+ {% if (!is_null(row[fieldname])) { %}
+ {%= row[fieldname] %}
+ {% } %}
+
+ {% } %}
+
+ {% } %}
+
+
+
+
Printed On {%= xhiveframework.datetime.str_to_user(xhiveframework.datetime.get_datetime_as_string()) %}
diff --git a/education/education/report/course_wise_assessment_report/course_wise_assessment_report.js b/education/education/report/course_wise_assessment_report/course_wise_assessment_report.js
new file mode 100644
index 0000000..92b591e
--- /dev/null
+++ b/education/education/report/course_wise_assessment_report/course_wise_assessment_report.js
@@ -0,0 +1,40 @@
+# Copyright (c) 2015, Xhive
+// For license information, please see license.txt
+
+xhiveframework.query_reports["Course wise Assessment Report"] = {
+ "filters": [
+ {
+ "fieldname":"academic_year",
+ "label": __("Academic Year"),
+ "fieldtype": "Link",
+ "options": "Academic Year",
+ "reqd": 1
+ },
+ {
+ "fieldname":"academic_term",
+ "label": __("Academic Term"),
+ "fieldtype": "Link",
+ "options": "Academic Term"
+ },
+ {
+ "fieldname":"course",
+ "label": __("Course"),
+ "fieldtype": "Link",
+ "options": "Course",
+ "reqd": 1
+ },
+ {
+ "fieldname":"student_group",
+ "label": __("Student Group"),
+ "fieldtype": "Link",
+ "options": "Student Group"
+ },
+ {
+ "fieldname":"assessment_group",
+ "label": __("Assessment Group"),
+ "fieldtype": "Link",
+ "options": "Assessment Group",
+ "reqd": 1
+ }
+ ]
+};
diff --git a/education/education/report/course_wise_assessment_report/course_wise_assessment_report.json b/education/education/report/course_wise_assessment_report/course_wise_assessment_report.json
new file mode 100644
index 0000000..ad5839b
--- /dev/null
+++ b/education/education/report/course_wise_assessment_report/course_wise_assessment_report.json
@@ -0,0 +1,28 @@
+{
+ "add_total_row": 0,
+ "creation": "2017-05-05 14:46:13.776133",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2020-06-24 17:15:15.477530",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Course wise Assessment Report",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "query": "",
+ "ref_doctype": "Assessment Result",
+ "report_name": "Course Wise Assessment Report",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Instructor"
+ },
+ {
+ "role": "Education Manager"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/education/education/report/course_wise_assessment_report/course_wise_assessment_report.py b/education/education/report/course_wise_assessment_report/course_wise_assessment_report.py
new file mode 100644
index 0000000..a297ae7
--- /dev/null
+++ b/education/education/report/course_wise_assessment_report/course_wise_assessment_report.py
@@ -0,0 +1,174 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+from collections import OrderedDict, defaultdict
+
+import xhiveframework
+from xhiveframework import _
+from xhiveframework.desk.treeview import get_children
+
+
+def execute(filters=None):
+ data, chart = [], []
+
+ if filters.get("assessment_group") == "All Assessment Groups":
+ xhiveframework.throw(
+ _("Please select the assessment group other than 'All Assessment Groups'")
+ )
+
+ data, criterias = get_data(filters)
+ columns = get_column(criterias)
+ chart = get_chart(data, criterias)
+
+ return columns, data, None, chart
+
+
+def get_data(filters):
+ data = []
+ criterias = []
+ values = get_formatted_result(filters)
+
+ for result in values.get("assessment_result"):
+ row = xhiveframework._dict()
+ row.student = result.get("student")
+ row.student_name = result.get("student_name")
+
+ for detail in result.details:
+ criteria = detail.get("assessment_criteria")
+ row[xhiveframework.scrub(criteria)] = detail.get("grade")
+ row[xhiveframework.scrub(criteria) + "_score"] = detail.get("score")
+ if not criteria in criterias:
+ criterias.append(criteria)
+
+ data.append(row)
+
+ return data, criterias
+
+
+def get_formatted_result(args, get_course=False):
+ courses = []
+ filters = prepare_filters(args)
+
+ assessment_result = xhiveframework.get_all(
+ "Assessment Result",
+ filters,
+ [
+ "student",
+ "student_name",
+ "name",
+ "course",
+ "assessment_group",
+ "total_score",
+ "grade",
+ ],
+ order_by="",
+ )
+
+ for result in assessment_result:
+ if get_course and result.course not in courses:
+ courses.append(result.course)
+
+ details = xhiveframework.get_all(
+ "Assessment Result Detail",
+ {
+ "parent": result.name,
+ },
+ ["assessment_criteria", "maximum_score", "grade", "score"],
+ )
+ result.update({"details": details})
+
+ return {"assessment_result": assessment_result, "courses": courses}
+
+
+def prepare_filters(args):
+ filters = {"academic_year": args.academic_year, "docstatus": 1}
+
+ options = ["course", "academic_term", "student_group"]
+ for option in options:
+ if args.get(option):
+ filters[option] = args.get(option)
+
+ assessment_groups = get_child_assessment_groups(args.assessment_group)
+
+ filters.update({"assessment_group": ["in", assessment_groups]})
+
+ if args.students:
+ filters.update({"student": ["in", args.students]})
+ return filters
+
+
+def get_column(criterias):
+ columns = [
+ {
+ "fieldname": "student",
+ "label": _("Student ID"),
+ "fieldtype": "Link",
+ "options": "Student",
+ "width": 150,
+ },
+ {
+ "fieldname": "student_name",
+ "label": _("Student Name"),
+ "fieldtype": "Data",
+ "width": 150,
+ },
+ ]
+ for criteria in criterias:
+ columns.append(
+ {
+ "fieldname": xhiveframework.scrub(criteria),
+ "label": criteria,
+ "fieldtype": "Data",
+ "width": 100,
+ }
+ )
+ columns.append(
+ {
+ "fieldname": xhiveframework.scrub(criteria) + "_score",
+ "label": "Score (" + criteria + ")",
+ "fieldtype": "Float",
+ "width": 100,
+ }
+ )
+
+ return columns
+
+
+def get_chart(data, criterias):
+ dataset = []
+ students = [row.student_name for row in data]
+
+ for criteria in criterias:
+ dataset_row = {"values": []}
+ dataset_row["name"] = criteria
+ for row in data:
+ if xhiveframework.scrub(criteria) + "_score" in row:
+ dataset_row["values"].append(row[xhiveframework.scrub(criteria) + "_score"])
+ else:
+ dataset_row["values"].append(0)
+
+ dataset.append(dataset_row)
+
+ charts = {
+ "data": {"labels": students, "datasets": dataset},
+ "type": "bar",
+ "colors": ["#ff0e0e", "#ff9966", "#ffcc00", "#99cc33", "#339900"],
+ }
+
+ return charts
+
+
+def get_child_assessment_groups(assessment_group):
+ assessment_groups = []
+ group_type = xhiveframework.get_value("Assessment Group", assessment_group, "is_group")
+ if group_type:
+
+ assessment_groups = [
+ d.get("value")
+ for d in get_children("Assessment Group", assessment_group)
+ if d.get("value") and not d.get("expandable")
+ ]
+ else:
+ assessment_groups = [assessment_group]
+ return assessment_groups
diff --git a/education/education/report/final_assessment_grades/__init__.py b/education/education/report/final_assessment_grades/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/report/final_assessment_grades/final_assessment_grades.js b/education/education/report/final_assessment_grades/final_assessment_grades.js
new file mode 100644
index 0000000..7837694
--- /dev/null
+++ b/education/education/report/final_assessment_grades/final_assessment_grades.js
@@ -0,0 +1,38 @@
+# Copyright (c) 2015, Xhive
+// For license information, please see license.txt
+/* eslint-disable */
+
+xhiveframework.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": xhiveframework.query_report.get_filter_value('academic_year')
+ }
+ };
+ }
+ },
+ {
+ "fieldname":"assessment_group",
+ "label": __("Assessment Group"),
+ "fieldtype": "Link",
+ "options": "Assessment Group",
+ "reqd": 1
+ }
+
+ ]
+}
diff --git a/education/education/report/final_assessment_grades/final_assessment_grades.json b/education/education/report/final_assessment_grades/final_assessment_grades.json
new file mode 100644
index 0000000..6a23494
--- /dev/null
+++ b/education/education/report/final_assessment_grades/final_assessment_grades.json
@@ -0,0 +1,27 @@
+{
+ "add_total_row": 0,
+ "creation": "2018-01-22 17:04:43.412054",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2020-06-24 17:13:35.373756",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Final Assessment Grades",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Assessment Result",
+ "report_name": "Final Assessment Grades",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Instructor"
+ },
+ {
+ "role": "Education Manager"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/education/education/report/final_assessment_grades/final_assessment_grades.py b/education/education/report/final_assessment_grades/final_assessment_grades.py
new file mode 100644
index 0000000..93e0d4b
--- /dev/null
+++ b/education/education/report/final_assessment_grades/final_assessment_grades.py
@@ -0,0 +1,119 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+import xhiveframework
+from xhiveframework import _
+
+from education.education.report.course_wise_assessment_report.course_wise_assessment_report import \
+ get_formatted_result
+
+
+def execute(filters=None):
+ columns, data = [], []
+
+ data, course_list = get_data(data, filters)
+ columns = get_column(course_list)
+ chart = get_chart(data, course_list)
+
+ return columns, data, None, chart
+
+
+def get_data(data, filters):
+ args = xhiveframework._dict()
+ args["academic_year"] = filters.get("academic_year")
+ args["assessment_group"] = filters.get("assessment_group")
+
+ args.students = xhiveframework.get_all(
+ "Student Group Student", {"parent": filters.get("student_group")}, pluck="student"
+ )
+
+ values = get_formatted_result(args, get_course=True)
+ assessment_result = values.get("assessment_result")
+ course_list = values.get("courses")
+
+ for result in assessment_result:
+ exists = [i for i, d in enumerate(data) if d.get("student") == result.student]
+ if not len(exists):
+ row = xhiveframework._dict()
+ row.student = result.student
+ row.student_name = result.student_name
+ row.assessment_group = result.assessment_group
+ row["grade_" + xhiveframework.scrub(result.course)] = result.grade
+ row["score_" + xhiveframework.scrub(result.course)] = result.total_score
+
+ data.append(row)
+ else:
+ index = exists[0]
+ data[index]["grade_" + xhiveframework.scrub(result.course)] = result.grade
+ data[index]["score_" + xhiveframework.scrub(result.course)] = result.total_score
+
+ return data, course_list
+
+
+def get_column(course_list):
+ columns = [
+ {
+ "fieldname": "student",
+ "label": _("Student ID"),
+ "fieldtype": "Link",
+ "options": "Student",
+ "width": 150,
+ },
+ {
+ "fieldname": "student_name",
+ "label": _("Student Name"),
+ "fieldtype": "Data",
+ "width": 120,
+ },
+ {
+ "fieldname": "assessment_group",
+ "label": _("Assessment Group"),
+ "fieldtype": "Link",
+ "options": "Assessment Group",
+ "width": 100,
+ },
+ ]
+ for course in course_list:
+ columns.append(
+ {
+ "fieldname": "grade_" + xhiveframework.scrub(course),
+ "label": course,
+ "fieldtype": "Data",
+ "width": 100,
+ }
+ )
+ columns.append(
+ {
+ "fieldname": "score_" + xhiveframework.scrub(course),
+ "label": "Score (" + course + ")",
+ "fieldtype": "Float",
+ "width": 150,
+ }
+ )
+
+ return columns
+
+
+def get_chart(data, course_list):
+ dataset = []
+ students = [row.student_name for row in data]
+
+ for course in course_list:
+ dataset_row = {"values": []}
+ dataset_row["name"] = course
+ for row in data:
+ if "score_" + xhiveframework.scrub(course) in row:
+ dataset_row["values"].append(row["score_" + xhiveframework.scrub(course)])
+ else:
+ dataset_row["values"].append(0)
+
+ dataset.append(dataset_row)
+
+ charts = {
+ "data": {"labels": students, "datasets": dataset},
+ "type": "bar",
+ "colors": ["#ff0e0e", "#ff9966", "#ffcc00", "#99cc33", "#339900"],
+ }
+
+ return charts
diff --git a/education/education/report/program_wise_fee_collection/__init__.py b/education/education/report/program_wise_fee_collection/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/report/program_wise_fee_collection/program_wise_fee_collection.js b/education/education/report/program_wise_fee_collection/program_wise_fee_collection.js
new file mode 100644
index 0000000..6cafb34
--- /dev/null
+++ b/education/education/report/program_wise_fee_collection/program_wise_fee_collection.js
@@ -0,0 +1,22 @@
+# Copyright (c) 2015, Xhive
+// For license information, please see license.txt
+/* eslint-disable */
+
+xhiveframework.query_reports["Program wise Fee Collection"] = {
+ "filters": [
+ {
+ "fieldname": "from_date",
+ "label": __("From Date"),
+ "fieldtype": "Date",
+ "default": xhiveframework.datetime.add_months(xhiveframework.datetime.get_today(), -1),
+ "reqd": 1
+ },
+ {
+ "fieldname": "to_date",
+ "label": __("To Date"),
+ "fieldtype": "Date",
+ "default": xhiveframework.datetime.get_today(),
+ "reqd": 1
+ }
+ ]
+};
diff --git a/education/education/report/program_wise_fee_collection/program_wise_fee_collection.json b/education/education/report/program_wise_fee_collection/program_wise_fee_collection.json
new file mode 100644
index 0000000..ee5c0de
--- /dev/null
+++ b/education/education/report/program_wise_fee_collection/program_wise_fee_collection.json
@@ -0,0 +1,32 @@
+{
+ "add_total_row": 1,
+ "creation": "2020-07-27 16:05:33.263539",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "json": "{}",
+ "modified": "2020-08-05 14:14:12.410515",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Program wise Fee Collection",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "query": "SELECT \n FeesCollected.program AS \"Program:Link/Program:200\",\n FeesCollected.paid_amount AS \"Fees Collected:Currency:150\",\n FeesCollected.outstanding_amount AS \"Outstanding Amount:Currency:150\",\n FeesCollected.grand_total \"Grand Total:Currency:150\"\nFROM (\n SELECT \n sum(grand_total) - sum(outstanding_amount) AS paid_amount, program,\n sum(outstanding_amount) AS outstanding_amount,\n sum(grand_total) AS grand_total\n FROM `tabFees`\n WHERE docstatus = 1\n GROUP BY program\n) AS FeesCollected\nORDER BY FeesCollected.paid_amount DESC",
+ "ref_doctype": "Fees",
+ "report_name": "Program wise Fee Collection",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Academics User"
+ },
+ {
+ "role": "Accounts User"
+ },
+ {
+ "role": "Accounts Manager"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/education/education/report/program_wise_fee_collection/program_wise_fee_collection.py b/education/education/report/program_wise_fee_collection/program_wise_fee_collection.py
new file mode 100644
index 0000000..332daef
--- /dev/null
+++ b/education/education/report/program_wise_fee_collection/program_wise_fee_collection.py
@@ -0,0 +1,127 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+import xhiveframework
+from xhiveframework import _
+
+
+def execute(filters=None):
+ if not filters:
+ filters = {}
+
+ columns = get_columns(filters)
+ data = get_data(filters)
+ chart = get_chart_data(data)
+
+ return columns, data, None, chart
+
+
+def get_columns(filters=None):
+ return [
+ {
+ "label": _("Program"),
+ "fieldname": "program",
+ "fieldtype": "Link",
+ "options": "Program",
+ "width": 300,
+ },
+ {
+ "label": _("Fees Collected"),
+ "fieldname": "fees_collected",
+ "fieldtype": "Currency",
+ "width": 200,
+ },
+ {
+ "label": _("Outstanding Amount"),
+ "fieldname": "outstanding_amount",
+ "fieldtype": "Currency",
+ "width": 200,
+ },
+ {
+ "label": _("Grand Total"),
+ "fieldname": "grand_total",
+ "fieldtype": "Currency",
+ "width": 200,
+ },
+ ]
+
+
+def get_data(filters=None):
+ data = []
+
+ conditions = get_filter_conditions(filters)
+
+ fee_details = xhiveframework.db.sql(
+ """
+ SELECT
+ FeesCollected.program,
+ FeesCollected.paid_amount,
+ FeesCollected.outstanding_amount,
+ FeesCollected.grand_total
+ FROM (
+ SELECT
+ sum(grand_total) - sum(outstanding_amount) AS paid_amount, program,
+ sum(outstanding_amount) AS outstanding_amount,
+ sum(grand_total) AS grand_total
+ FROM `tabFees`
+ WHERE
+ docstatus = 1 and
+ program IS NOT NULL
+ %s
+ GROUP BY program
+ ) AS FeesCollected
+ ORDER BY FeesCollected.paid_amount DESC
+ """
+ % (conditions),
+ as_dict=1,
+ )
+
+ for entry in fee_details:
+ data.append(
+ {
+ "program": entry.program,
+ "fees_collected": entry.paid_amount,
+ "outstanding_amount": entry.outstanding_amount,
+ "grand_total": entry.grand_total,
+ }
+ )
+
+ return data
+
+
+def get_filter_conditions(filters):
+ conditions = ""
+
+ if filters.get("from_date") and filters.get("to_date"):
+ conditions += " and posting_date BETWEEN '%s' and '%s'" % (
+ filters.get("from_date"),
+ filters.get("to_date"),
+ )
+
+ return conditions
+
+
+def get_chart_data(data):
+ if not data:
+ return
+
+ labels = []
+ fees_collected = []
+ outstanding_amount = []
+
+ for entry in data:
+ labels.append(entry.get("program"))
+ fees_collected.append(entry.get("fees_collected"))
+ outstanding_amount.append(entry.get("outstanding_amount"))
+
+ return {
+ "data": {
+ "labels": labels,
+ "datasets": [
+ {"name": _("Fees Collected"), "values": fees_collected},
+ {"name": _("Outstanding Amt"), "values": outstanding_amount},
+ ],
+ },
+ "type": "bar",
+ }
diff --git a/education/education/report/student_and_guardian_contact_details/__init__.py b/education/education/report/student_and_guardian_contact_details/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.js b/education/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.js
new file mode 100644
index 0000000..4954453
--- /dev/null
+++ b/education/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.js
@@ -0,0 +1,29 @@
+# Copyright (c) 2015, Xhive
+// For license information, please see license.txt
+
+xhiveframework.query_reports["Student and Guardian Contact Details"] = {
+ "filters": [
+ {
+ "fieldname":"academic_year",
+ "label": __("Academic Year"),
+ "fieldtype": "Link",
+ "options": "Academic Year",
+ "reqd": 1,
+ },
+ {
+ "fieldname":"program",
+ "label": __("Program"),
+ "fieldtype": "Link",
+ "options": "Program",
+ "reqd": 1
+ },
+ {
+ "fieldname":"student_batch_name",
+ "label": __("Batch Name"),
+ "fieldtype": "Link",
+ "options": "Student Batch Name",
+ "reqd": 1
+ },
+
+ ]
+}
diff --git a/education/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.json b/education/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.json
new file mode 100644
index 0000000..fa9be65
--- /dev/null
+++ b/education/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.json
@@ -0,0 +1,27 @@
+{
+ "add_total_row": 0,
+ "creation": "2017-03-27 17:47:16.831433",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2020-06-24 17:16:50.639488",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student and Guardian Contact Details",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Program Enrollment",
+ "report_name": "Student and Guardian Contact Details",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Instructor"
+ },
+ {
+ "role": "Academics User"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/education/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py b/education/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py
new file mode 100644
index 0000000..65406c7
--- /dev/null
+++ b/education/education/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py
@@ -0,0 +1,230 @@
+# Copyright (c) 2015, Xhive
+# For license information, please see license.txt
+
+
+import xhiveframework
+from xhiveframework import _
+
+
+def execute(filters=None):
+ columns, data = [], []
+
+ academic_year = filters.get("academic_year")
+ program = filters.get("program")
+ student_batch_name = filters.get("student_batch_name")
+
+ columns = get_columns()
+
+ program_enrollments = xhiveframework.get_list(
+ "Program Enrollment",
+ fields=["student", "student_name"],
+ filters={
+ "academic_year": academic_year,
+ "program": program,
+ "student_batch_name": student_batch_name,
+ },
+ )
+
+ student_list = [d.student for d in program_enrollments]
+ if not student_list:
+ return columns, []
+
+ group_roll_no_map = get_student_roll_no(academic_year, program, student_batch_name)
+ student_map = get_student_details(student_list)
+ guardian_map = get_guardian_map(student_list)
+
+ for d in program_enrollments:
+ student_details = student_map.get(d.student, {})
+
+ row = xhiveframework._dict(
+ {
+ "group_roll_no": group_roll_no_map.get(d.student, ""),
+ "student_id": d.student,
+ "student_name": d.student_name,
+ "student_mobile_no": student_details.get("student_mobile_number", ""),
+ "student_email_id": student_details.get("student_email_id", ""),
+ "student_address": student_details.get("address", ""),
+ }
+ )
+
+ student_guardians = guardian_map.get(d.student, [])
+ # only 2 guardians per student
+ for i, g in enumerate(student_guardians[:2]):
+ row[f"guardian{i+1}_name"] = g.guardian_name
+ row[f"relation_with_guardian{i+1}"] = g.relation
+ row[f"guardian{i+1}_mobile_no"] = g.mobile_number
+ row[f"guardian{i+1}_email_id"] = g.email_address
+
+ data.append(row)
+
+ return columns, data
+
+
+def get_columns():
+ columns = [
+ {
+ "label": _("Group Roll No"),
+ "fieldname": "group_roll_no",
+ "fieldtype": "Data",
+ "width": 60,
+ },
+ {
+ "label": _("Student ID"),
+ "fieldname": "student_id",
+ "fieldtype": "Link",
+ "options": "Student",
+ "width": 90,
+ },
+ {
+ "label": _("Student Name"),
+ "fieldname": "student_name",
+ "fieldtype": "Data",
+ "width": 150,
+ },
+ {
+ "label": _("Student Mobile No."),
+ "fieldname": "student_mobile_no",
+ "fieldtype": "Data",
+ "width": 110,
+ },
+ {
+ "label": _("Student Email ID"),
+ "fieldname": "student_email_id",
+ "fieldtype": "Data",
+ "width": 125,
+ },
+ {
+ "label": _("Student Address"),
+ "fieldname": "student_address",
+ "fieldtype": "Data",
+ "width": 175,
+ },
+ {
+ "label": _("Guardian1 Name"),
+ "fieldname": "guardian1_name",
+ "fieldtype": "Data",
+ "width": 150,
+ },
+ {
+ "label": _("Relation with Guardian1"),
+ "fieldname": "relation_with_guardian1",
+ "fieldtype": "Data",
+ "width": 80,
+ },
+ {
+ "label": _("Guardian1 Mobile No"),
+ "fieldname": "guardian1_mobile_no",
+ "fieldtype": "Data",
+ "width": 125,
+ },
+ {
+ "label": _("Guardian1 Email ID"),
+ "fieldname": "guardian1_email_id",
+ "fieldtype": "Data",
+ "width": 125,
+ },
+ {
+ "label": _("Guardian2 Name"),
+ "fieldname": "guardian2_name",
+ "fieldtype": "Data",
+ "width": 150,
+ },
+ {
+ "label": _("Relation with Guardian2"),
+ "fieldname": "relation_with_guardian2",
+ "fieldtype": "Data",
+ "width": 80,
+ },
+ {
+ "label": _("Guardian2 Mobile No"),
+ "fieldname": "guardian2_mobile_no",
+ "fieldtype": "Data",
+ "width": 125,
+ },
+ {
+ "label": _("Guardian2 Email ID"),
+ "fieldname": "guardian2_email_id",
+ "fieldtype": "Data",
+ "width": 125,
+ },
+ ]
+ return columns
+
+
+def get_student_details(student_list):
+ student_map = xhiveframework._dict()
+ student_details = xhiveframework.db.sql(
+ """
+ select name, student_mobile_number, student_email_id, address_line_1, address_line_2, city, state from `tabStudent` where name in (%s)"""
+ % ", ".join(["%s"] * len(student_list)),
+ tuple(student_list),
+ as_dict=1,
+ )
+ for s in student_details:
+ student = xhiveframework._dict()
+ student["student_mobile_number"] = s.student_mobile_number
+ student["student_email_id"] = s.student_email_id
+ student["address"] = ", ".join(
+ [d for d in [s.address_line_1, s.address_line_2, s.city, s.state] if d]
+ )
+ student_map[s.name] = student
+ return student_map
+
+
+def get_guardian_map(student_list):
+ guardian_map = xhiveframework._dict()
+ guardian_details = xhiveframework.db.sql(
+ """
+ select parent, guardian, guardian_name, relation from `tabStudent Guardian` where parent in (%s)"""
+ % ", ".join(["%s"] * len(student_list)),
+ tuple(student_list),
+ as_dict=1,
+ )
+
+ guardian_list = list(set([g.guardian for g in guardian_details])) or [""]
+
+ guardian_mobile_no = dict(
+ xhiveframework.db.sql(
+ """select name, mobile_number from `tabGuardian`
+ where name in (%s)"""
+ % ", ".join(["%s"] * len(guardian_list)),
+ tuple(guardian_list),
+ )
+ )
+
+ guardian_email_id = dict(
+ xhiveframework.db.sql(
+ """select name, email_address from `tabGuardian`
+ where name in (%s)"""
+ % ", ".join(["%s"] * len(guardian_list)),
+ tuple(guardian_list),
+ )
+ )
+
+ for guardian in guardian_details:
+ guardian["mobile_number"] = guardian_mobile_no.get(guardian.guardian)
+ guardian["email_address"] = guardian_email_id.get(guardian.guardian)
+ guardian_map.setdefault(guardian.parent, []).append(guardian)
+
+ return guardian_map
+
+
+def get_student_roll_no(academic_year, program, batch):
+ student_group = xhiveframework.get_all(
+ "Student Group",
+ filters={
+ "academic_year": academic_year,
+ "program": program,
+ "batch": batch,
+ "disabled": 0,
+ },
+ )
+ if student_group:
+ roll_no_dict = dict(
+ xhiveframework.db.sql(
+ """select student, group_roll_number from `tabStudent Group Student` where parent=%s""",
+ (student_group[0].name),
+ )
+ )
+ return roll_no_dict
+ return {}
diff --git a/education/education/report/student_batch_wise_attendance/__init__.py b/education/education/report/student_batch_wise_attendance/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/report/student_batch_wise_attendance/student_batch_wise_attendance.js b/education/education/report/student_batch_wise_attendance/student_batch_wise_attendance.js
new file mode 100644
index 0000000..68104dd
--- /dev/null
+++ b/education/education/report/student_batch_wise_attendance/student_batch_wise_attendance.js
@@ -0,0 +1,12 @@
+# Copyright (c) 2015, Xhive
+// For license information, please see license.txt
+
+xhiveframework.query_reports["Student Batch-Wise Attendance"] = {
+ "filters": [{
+ "fieldname": "date",
+ "label": __("Date"),
+ "fieldtype": "Date",
+ "default": xhiveframework.datetime.get_today(),
+ "reqd": 1
+ }]
+}
diff --git a/education/education/report/student_batch_wise_attendance/student_batch_wise_attendance.json b/education/education/report/student_batch_wise_attendance/student_batch_wise_attendance.json
new file mode 100644
index 0000000..8baf8f9
--- /dev/null
+++ b/education/education/report/student_batch_wise_attendance/student_batch_wise_attendance.json
@@ -0,0 +1,24 @@
+{
+ "add_total_row": 0,
+ "creation": "2016-11-28 22:07:03.859124",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 2,
+ "is_standard": "Yes",
+ "modified": "2020-06-24 17:16:59.823709",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Batch-Wise Attendance",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Student Attendance",
+ "report_name": "Student Batch-Wise Attendance",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Academics User"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/education/education/report/student_batch_wise_attendance/student_batch_wise_attendance.py b/education/education/report/student_batch_wise_attendance/student_batch_wise_attendance.py
new file mode 100644
index 0000000..dca5cd1
--- /dev/null
+++ b/education/education/report/student_batch_wise_attendance/student_batch_wise_attendance.py
@@ -0,0 +1,92 @@
+# Copyright (c) 2015, Xhive
+# License: GNU General Public License v3. See license.txt
+
+
+import xhiveframework
+from xhiveerp.setup.doctype.holiday_list.holiday_list import is_holiday
+from xhiveframework import _, msgprint
+from xhiveframework.utils import formatdate
+
+from education.education.doctype.student_attendance.student_attendance import \
+ get_holiday_list
+
+
+def execute(filters=None):
+ if not filters:
+ filters = {}
+
+ if not filters.get("date"):
+ msgprint(_("Please select date"), raise_exception=1)
+
+ holiday_list = get_holiday_list()
+ if is_holiday(holiday_list, filters.get("date")):
+ msgprint(
+ _("No attendance has been marked for {0} as it is a Holiday").format(
+ xhiveframework.bold(formatdate(filters.get("date")))
+ )
+ )
+
+ columns = get_columns(filters)
+
+ active_student_group = get_active_student_group()
+
+ data = []
+ for student_group in active_student_group:
+ row = [student_group.name]
+ present_students = 0
+ absent_students = 0
+ student_group_strength = get_student_group_strength(student_group.name)
+ student_attendance = get_student_attendance(student_group.name, filters.get("date"))
+ if student_attendance:
+ for attendance in student_attendance:
+ if attendance.status == "Present":
+ present_students = attendance.count
+ elif attendance.status == "Absent":
+ absent_students = attendance.count
+
+ unmarked_students = student_group_strength - (present_students + absent_students)
+ row += [student_group_strength, present_students, absent_students, unmarked_students]
+ data.append(row)
+
+ return columns, data
+
+
+def get_columns(filters):
+ columns = [
+ _("Student Group") + ":Link/Student Group:250",
+ _("Student Group Strength") + "::170",
+ _("Present") + "::90",
+ _("Absent") + "::90",
+ _("Not Marked") + "::90",
+ ]
+ return columns
+
+
+def get_active_student_group():
+ active_student_groups = xhiveframework.db.sql(
+ """select name from `tabStudent Group` where group_based_on = "Batch"
+ and academic_year=%s order by name""",
+ (xhiveframework.defaults.get_defaults().academic_year),
+ as_dict=1,
+ )
+ return active_student_groups
+
+
+def get_student_group_strength(student_group):
+ student_group_strength = xhiveframework.db.sql(
+ """select count(*) from `tabStudent Group Student`
+ where parent = %s and active=1""",
+ student_group,
+ )[0][0]
+ return student_group_strength
+
+
+def get_student_attendance(student_group, date):
+ student_attendance = xhiveframework.db.sql(
+ """select count(*) as count, status from `tabStudent Attendance` where
+ student_group= %s and date= %s and docstatus = 1 and
+ (course_schedule is Null or course_schedule='') group by status""",
+ (student_group, date),
+ as_dict=1,
+ )
+ return student_attendance
diff --git a/education/education/report/student_fee_collection/__init__.py b/education/education/report/student_fee_collection/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/report/student_fee_collection/student_fee_collection.json b/education/education/report/student_fee_collection/student_fee_collection.json
new file mode 100644
index 0000000..c0229a2
--- /dev/null
+++ b/education/education/report/student_fee_collection/student_fee_collection.json
@@ -0,0 +1,25 @@
+{
+ "add_total_row": 1,
+ "creation": "2016-06-22 02:58:41.024538",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 3,
+ "is_standard": "Yes",
+ "modified": "2020-06-24 17:14:39.452551",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Fee Collection",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "query": "SELECT\n student as \"Student:Link/Student:200\",\n student_name as \"Student Name::200\",\n sum(grand_total) - sum(outstanding_amount) as \"Paid Amount:Currency:150\",\n sum(outstanding_amount) as \"Outstanding Amount:Currency:150\",\n sum(grand_total) as \"Grand Total:Currency:150\"\nFROM\n `tabFees` \nWHERE\n docstatus=1 \nGROUP BY\n student",
+ "ref_doctype": "Fees",
+ "report_name": "Student Fee Collection",
+ "report_type": "Query Report",
+ "roles": [
+ {
+ "role": "Academics User"
+ }
+ ]
+}
diff --git a/education/education/report/student_monthly_attendance_sheet/__init__.py b/education/education/report/student_monthly_attendance_sheet/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.js b/education/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.js
new file mode 100644
index 0000000..f2e418e
--- /dev/null
+++ b/education/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.js
@@ -0,0 +1,30 @@
+# Copyright (c) 2015, Xhive
+// License: GNU General Public License v3. See license.txt
+
+
+xhiveframework.query_reports["Student Monthly Attendance Sheet"] = {
+ "filters": [{
+ "fieldname": "month",
+ "label": __("Month"),
+ "fieldtype": "Select",
+ "options": "Jan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug\nSep\nOct\nNov\nDec",
+ "default": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov",
+ "Dec"
+ ][xhiveframework.datetime.str_to_obj(xhiveframework.datetime.get_today()).getMonth()],
+ },
+ {
+ "fieldname": "year",
+ "label": __("Year"),
+ "fieldtype": "Link",
+ "options":"Academic Year",
+ "reqd": 1
+ },
+ {
+ "fieldname": "student_group",
+ "label": __("Student Group"),
+ "fieldtype": "Link",
+ "options": "Student Group",
+ "reqd": 1
+ }
+ ],
+}
diff --git a/education/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.json b/education/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.json
new file mode 100644
index 0000000..1423d4f
--- /dev/null
+++ b/education/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.json
@@ -0,0 +1,24 @@
+{
+ "add_total_row": 0,
+ "creation": "2013-05-13 14:04:03",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 3,
+ "is_standard": "Yes",
+ "modified": "2020-06-24 17:16:13.307053",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Student Monthly Attendance Sheet",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Student Attendance",
+ "report_name": "Student Monthly Attendance Sheet",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Academics User"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/education/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py b/education/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py
new file mode 100644
index 0000000..a1112e4
--- /dev/null
+++ b/education/education/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py
@@ -0,0 +1,161 @@
+# Copyright (c) 2015, Xhive
+# License: GNU General Public License v3. See license.txt
+
+
+import xhiveframework
+from xhiveerp.support.doctype.issue.issue import get_holidays
+from xhiveframework import _
+from xhiveframework.utils import add_days, cstr, date_diff, get_first_day, get_last_day, getdate
+
+from education.education.api import get_student_group_students
+from education.education.doctype.student_attendance.student_attendance import (
+ get_holiday_list,
+)
+
+
+def execute(filters=None):
+ if not filters:
+ filters = {}
+
+ filter_year = str(
+ xhiveframework.db.get_value(
+ "Academic Year", {"name": filters["year"]}, fieldname="year_start_date"
+ ).year
+ )
+
+ from_date = get_first_day(filters["month"] + "-" + filter_year)
+ to_date = get_last_day(filters["month"] + "-" + filter_year)
+
+ total_days_in_month = date_diff(to_date, from_date) + 1
+ columns = get_columns(total_days_in_month)
+ students = get_student_group_students(filters.get("student_group"), 1)
+ students_list = get_students_list(students)
+ att_map = get_attendance_list(
+ from_date, to_date, filters.get("student_group"), students_list
+ )
+ data = []
+
+ for stud in students:
+ row = [stud.student, stud.student_name]
+ student_status = xhiveframework.db.get_value("Student", stud.student, "enabled")
+ date = from_date
+ total_p = total_a = 0.0
+
+ for day in range(total_days_in_month):
+ status = "None"
+
+ if att_map.get(stud.student):
+ status = att_map.get(stud.student).get(date, "None")
+ elif not student_status:
+ status = "Inactive"
+ else:
+ status = "None"
+
+ status_map = {
+ "Present": "P",
+ "Absent": "A",
+ "None": "",
+ "Inactive": "-",
+ "Holiday": "H",
+ }
+ row.append(status_map[status])
+
+ if status == "Present":
+ total_p += 1
+ elif status == "Absent":
+ total_a += 1
+ date = add_days(date, 1)
+
+ row += [total_p, total_a]
+ data.append(row)
+ return columns, data
+
+
+def get_columns(days_in_month):
+ columns = [_("Student") + ":Link/Student:90", _("Student Name") + "::150"]
+ for day in range(days_in_month):
+ columns.append(cstr(day + 1) + "::20")
+ columns += [_("Total Present") + ":Int:95", _("Total Absent") + ":Int:90"]
+ return columns
+
+
+def get_students_list(students):
+ student_list = []
+ for stud in students:
+ student_list.append(stud.student)
+ return student_list
+
+
+def get_attendance_list(from_date, to_date, student_group, students_list):
+ attendance_list = xhiveframework.db.sql(
+ """select student, date, status
+ from `tabStudent Attendance` where student_group = %s
+ and docstatus = 1
+ and date between %s and %s
+ order by student, date""",
+ (student_group, from_date, to_date),
+ as_dict=1,
+ )
+
+ att_map = {}
+ students_with_leave_application = get_students_with_leave_application(
+ from_date, to_date, students_list
+ )
+ for d in attendance_list:
+ att_map.setdefault(d.student, xhiveframework._dict()).setdefault(d.date, "")
+
+ if students_with_leave_application.get(
+ d.date
+ ) and d.student in students_with_leave_application.get(d.date):
+ att_map[d.student][d.date] = "Present"
+ else:
+ att_map[d.student][d.date] = d.status
+
+ att_map = mark_holidays(att_map, from_date, to_date, students_list)
+
+ return att_map
+
+
+def get_students_with_leave_application(from_date, to_date, students_list):
+ if not students_list:
+ return
+ leave_applications = xhiveframework.db.sql(
+ """
+ select student, from_date, to_date
+ from `tabStudent Leave Application`
+ where
+ mark_as_present = 1 and docstatus = 1
+ and student in %(students)s
+ and (
+ from_date between %(from_date)s and %(to_date)s
+ or to_date between %(from_date)s and %(to_date)s
+ or (%(from_date)s between from_date and to_date and %(to_date)s between from_date and to_date)
+ )
+ """,
+ {"students": students_list, "from_date": from_date, "to_date": to_date},
+ as_dict=True,
+ )
+ students_with_leaves = {}
+ for application in leave_applications:
+ for date in daterange(application.from_date, application.to_date):
+ students_with_leaves.setdefault(date, []).append(application.student)
+
+ return students_with_leaves
+
+
+def daterange(d1, d2):
+ import datetime
+
+ return (d1 + datetime.timedelta(days=i) for i in range((d2 - d1).days + 1))
+
+
+def mark_holidays(att_map, from_date, to_date, students_list):
+ holiday_list = get_holiday_list()
+ holidays = get_holidays(holiday_list)
+
+ for dt in daterange(getdate(from_date), getdate(to_date)):
+ if dt in holidays:
+ for student in students_list:
+ att_map.setdefault(student, xhiveframework._dict()).setdefault(dt, "Holiday")
+
+ return att_map
diff --git a/education/education/utils.py b/education/education/utils.py
new file mode 100644
index 0000000..7a6aa9e
--- /dev/null
+++ b/education/education/utils.py
@@ -0,0 +1,434 @@
+# Copyright (c) 2015, Xhive
+
+import xhiveframework
+from xhiveframework import _
+
+
+class OverlapError(xhiveframework.ValidationError):
+ pass
+
+
+def validate_overlap_for(doc, doctype, fieldname, value=None):
+ """Checks overlap for specified field.
+
+ :param fieldname: Checks Overlap for this field
+ """
+
+ existing = get_overlap_for(doc, doctype, fieldname, value)
+ if existing:
+ xhiveframework.throw(
+ _("This {0} conflicts with {1} for {2} {3}").format(
+ doc.doctype,
+ existing.name,
+ doc.meta.get_label(fieldname) if not value else fieldname,
+ value or doc.get(fieldname),
+ ),
+ OverlapError,
+ )
+
+
+def get_overlap_for(doc, doctype, fieldname, value=None):
+ """Returns overlaping document for specified field.
+
+ :param fieldname: Checks Overlap for this field
+ """
+
+ existing = xhiveframework.db.sql(
+ """select name, from_time, to_time from `tab{0}`
+ where `{1}`=%(val)s and schedule_date = %(schedule_date)s and
+ (
+ (from_time > %(from_time)s and from_time < %(to_time)s) or
+ (to_time > %(from_time)s and to_time < %(to_time)s) or
+ (%(from_time)s > from_time and %(from_time)s < to_time) or
+ (%(from_time)s = from_time and %(to_time)s = to_time))
+ and name!=%(name)s and docstatus!=2""".format(
+ doctype, fieldname
+ ),
+ {
+ "schedule_date": doc.schedule_date,
+ "val": value or doc.get(fieldname),
+ "from_time": doc.from_time,
+ "to_time": doc.to_time,
+ "name": doc.name or "No Name",
+ },
+ as_dict=True,
+ )
+
+ return existing[0] if existing else None
+
+
+def validate_duplicate_student(students):
+ unique_students = []
+ for stud in students:
+ if stud.student in unique_students:
+ xhiveframework.throw(
+ _("Student {0} - {1} appears Multiple times in row {2} & {3}").format(
+ stud.student, stud.student_name, unique_students.index(stud.student) + 1, stud.idx
+ )
+ )
+ else:
+ unique_students.append(stud.student)
+
+ return None
+
+
+# LMS Utils
+def get_current_student():
+ """Returns current student from xhiveframework.session.user
+
+ Returns:
+ object: Student Document
+ """
+ email = xhiveframework.session.user
+ if email in ("Administrator", "Guest"):
+ return None
+ try:
+ student_id = xhiveframework.get_all("Student", {"student_email_id": email}, ["name"])[0].name
+ return xhiveframework.get_doc("Student", student_id)
+ except (IndexError, xhiveframework.DoesNotExistError):
+ return None
+
+
+def get_enrollment(master, document, student):
+ """Gets enrollment for course or program
+
+ Args:
+ master (string): can either be program or course
+ document (string): program or course name
+ student (string): Student ID
+
+ Returns:
+ string: Enrollment Name if exists else returns empty string
+ """
+ if master == "program":
+ enrollments = xhiveframework.get_all(
+ "Program Enrollment",
+ filters={"student": student, "program": document, "docstatus": 1},
+ )
+ if master == "course":
+ enrollments = xhiveframework.get_all(
+ "Course Enrollment", filters={"student": student, "course": document}
+ )
+
+ if enrollments:
+ return enrollments[0].name
+ else:
+ return None
+
+
+@xhiveframework.whitelist()
+def enroll_in_program(program_name, student=None):
+ """Enroll student in program
+
+ Args:
+ program_name (string): Name of the program to be enrolled into
+ student (string, optional): name of student who has to be enrolled, if not
+ provided, a student will be created from the current user
+
+ Returns:
+ string: name of the program enrollment document
+ """
+ if has_super_access():
+ return
+
+ if not student == None:
+ student = xhiveframework.get_doc("Student", student)
+ else:
+ # Check if self enrollment in allowed
+ program = xhiveframework.get_doc("Program", program_name)
+ if not program.allow_self_enroll:
+ return xhiveframework.throw(_("You are not allowed to enroll for this course"))
+
+ student = get_current_student()
+ if not student:
+ student = create_student_from_current_user()
+
+ # Check if student is already enrolled in program
+ enrollment = get_enrollment("program", program_name, student.name)
+ if enrollment:
+ return enrollment
+
+ # Check if self enrollment in allowed
+ program = xhiveframework.get_doc("Program", program_name)
+ if not program.allow_self_enroll:
+ return xhiveframework.throw(_("You are not allowed to enroll for this course"))
+
+ # Enroll in program
+ program_enrollment = student.enroll_in_program(program_name)
+ return program_enrollment.name
+
+
+def has_super_access():
+ """Check if user has a role that allows full access to LMS
+
+ Returns:
+ bool: true if user has access to all lms content
+ """
+ current_user = xhiveframework.get_doc("User", xhiveframework.session.user)
+ roles = set([role.role for role in current_user.roles])
+ return bool(
+ roles
+ & {
+ "Administrator",
+ "Instructor",
+ "Education Manager",
+ "System Manager",
+ "Academic User",
+ }
+ )
+
+
+@xhiveframework.whitelist()
+def add_activity(course, content_type, content, program):
+ if has_super_access():
+ return None
+
+ student = get_current_student()
+ if not student:
+ return xhiveframework.throw(
+ _("Student with email {0} does not exist").format(xhiveframework.session.user),
+ xhiveframework.DoesNotExistError,
+ )
+
+ enrollment = get_or_create_course_enrollment(course, program)
+ if content_type == "Quiz":
+ return
+ else:
+ return enrollment.add_activity(content_type, content)
+
+
+@xhiveframework.whitelist()
+def evaluate_quiz(quiz_response, quiz_name, course, program, time_taken):
+ import json
+
+ student = get_current_student()
+
+ quiz_response = json.loads(quiz_response)
+ quiz = xhiveframework.get_doc("Quiz", quiz_name)
+ result, score, status = quiz.evaluate(quiz_response, quiz_name)
+
+ if has_super_access():
+ return {"result": result, "score": score, "status": status}
+
+ if student:
+ enrollment = get_or_create_course_enrollment(course, program)
+ if quiz.allowed_attempt(enrollment, quiz_name):
+ enrollment.add_quiz_activity(
+ quiz_name, quiz_response, result, score, status, time_taken
+ )
+ return {"result": result, "score": score, "status": status}
+ else:
+ return None
+
+
+@xhiveframework.whitelist()
+def get_quiz(quiz_name, course):
+ try:
+ quiz = xhiveframework.get_doc("Quiz", quiz_name)
+ questions = quiz.get_questions()
+ except Exception:
+ xhiveframework.throw(_("Quiz {0} does not exist").format(quiz_name), xhiveframework.DoesNotExistError)
+ return None
+
+ questions = [
+ {
+ "name": question.name,
+ "question": question.question,
+ "type": question.question_type,
+ "options": [
+ {"name": option.name, "option": option.option} for option in question.options
+ ],
+ }
+ for question in questions
+ ]
+
+ if has_super_access():
+ return {
+ "questions": questions,
+ "activity": None,
+ "is_time_bound": quiz.is_time_bound,
+ "duration": quiz.duration,
+ }
+
+ student = get_current_student()
+ course_enrollment = get_enrollment("course", course, student.name)
+ status, score, result, time_taken = check_quiz_completion(quiz, course_enrollment)
+ return {
+ "questions": questions,
+ "activity": {
+ "is_complete": status,
+ "score": score,
+ "result": result,
+ "time_taken": time_taken,
+ },
+ "is_time_bound": quiz.is_time_bound,
+ "duration": quiz.duration,
+ }
+
+
+def get_topic_progress(topic, course_name, program):
+ """
+ Return the porgress of a course in a program as well as the content to continue from.
+ :param topic_name:
+ :param course_name:
+ """
+ student = get_current_student()
+ if not student:
+ return None
+ course_enrollment = get_or_create_course_enrollment(course_name, program)
+ progress = student.get_topic_progress(course_enrollment.name, topic)
+ if not progress:
+ return None
+ count = sum([activity["is_complete"] for activity in progress])
+ if count == 0:
+ return {"completed": False, "started": False}
+ elif count == len(progress):
+ return {"completed": True, "started": True}
+ elif count < len(progress):
+ return {"completed": False, "started": True}
+
+
+def get_course_progress(course, program):
+ """
+ Return the porgress of a course in a program as well as the content to continue from.
+ :param topic_name:
+ :param course_name:
+ """
+ course_progress = []
+ for course_topic in course.topics:
+ topic = xhiveframework.get_doc("Topic", course_topic.topic)
+ progress = get_topic_progress(topic, course.name, program)
+ if progress:
+ course_progress.append(progress)
+ if course_progress:
+ number_of_completed_topics = sum(
+ [activity["completed"] for activity in course_progress]
+ )
+ total_topics = len(course_progress)
+ if total_topics == 1:
+ return course_progress[0]
+ if number_of_completed_topics == 0:
+ return {"completed": False, "started": False}
+ if number_of_completed_topics == total_topics:
+ return {"completed": True, "started": True}
+ if number_of_completed_topics < total_topics:
+ return {"completed": False, "started": True}
+
+ return None
+
+
+def get_program_progress(program):
+ program_progress = []
+ if not program.courses:
+ return None
+ for program_course in program.courses:
+ course = xhiveframework.get_doc("Course", program_course.course)
+ progress = get_course_progress(course, program.name)
+ if progress:
+ progress["name"] = course.name
+ progress["course"] = course.course_name
+ program_progress.append(progress)
+
+ if program_progress:
+ return program_progress
+
+ return None
+
+
+def get_program_completion(program):
+ topics = xhiveframework.db.sql(
+ """select `tabCourse Topic`.topic, `tabCourse Topic`.parent
+ from `tabCourse Topic`,
+ `tabProgram Course`
+ where `tabCourse Topic`.parent = `tabProgram Course`.course
+ and `tabProgram Course`.parent = %s""",
+ program.name,
+ )
+
+ progress = []
+ for topic in topics:
+ topic_doc = xhiveframework.get_doc("Topic", topic[0])
+ topic_progress = get_topic_progress(topic_doc, topic[1], program.name)
+ if topic_progress:
+ progress.append(topic_progress)
+
+ if progress:
+ number_of_completed_topics = sum(
+ [activity["completed"] for activity in progress if activity]
+ )
+ total_topics = len(progress)
+ try:
+ return int((float(number_of_completed_topics) / total_topics) * 100)
+ except ZeroDivisionError:
+ return 0
+
+ return 0
+
+
+def create_student_from_current_user():
+ user = xhiveframework.get_doc("User", xhiveframework.session.user)
+
+ student = xhiveframework.get_doc(
+ {
+ "doctype": "Student",
+ "first_name": user.first_name,
+ "last_name": user.last_name,
+ "student_email_id": user.email,
+ "user": xhiveframework.session.user,
+ }
+ )
+
+ student.save(ignore_permissions=True)
+ return student
+
+
+def get_or_create_course_enrollment(course, program):
+ student = get_current_student()
+ course_enrollment = get_enrollment("course", course, student.name)
+ if not course_enrollment:
+ program_enrollment = get_enrollment("program", program.name, student.name)
+ if not program_enrollment:
+ xhiveframework.throw(_("You are not enrolled in program {0}").format(program))
+ return
+ return student.enroll_in_course(
+ course_name=course,
+ program_enrollment=get_enrollment("program", program.name, student.name),
+ )
+ else:
+ return xhiveframework.get_doc("Course Enrollment", course_enrollment)
+
+
+def check_content_completion(content_name, content_type, enrollment_name):
+ activity = xhiveframework.get_all(
+ "Course Activity",
+ filters={
+ "enrollment": enrollment_name,
+ "content_type": content_type,
+ "content": content_name,
+ },
+ )
+ if activity:
+ return True
+ else:
+ return False
+
+
+def check_quiz_completion(quiz, enrollment_name):
+ attempts = xhiveframework.get_all(
+ "Quiz Activity",
+ filters={"enrollment": enrollment_name, "quiz": quiz.name},
+ fields=["name", "activity_date", "score", "status", "time_taken"],
+ )
+ status = False if quiz.max_attempts == 0 else bool(len(attempts) >= quiz.max_attempts)
+ score = None
+ result = None
+ time_taken = None
+ if attempts:
+ if quiz.grading_basis == "Last Highest Score":
+ attempts = sorted(attempts, key=lambda i: int(i.score), reverse=True)
+ score = attempts[0]["score"]
+ result = attempts[0]["status"]
+ time_taken = attempts[0]["time_taken"]
+ if result == "Pass":
+ status = True
+ return status, score, result, time_taken
diff --git a/education/education/web_form/__init__.py b/education/education/web_form/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/web_form/student_applicant/__init__.py b/education/education/web_form/student_applicant/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/education/web_form/student_applicant/student_applicant.js b/education/education/web_form/student_applicant/student_applicant.js
new file mode 100644
index 0000000..7de96c6
--- /dev/null
+++ b/education/education/web_form/student_applicant/student_applicant.js
@@ -0,0 +1,3 @@
+xhiveframework.ready(function() {
+ // bind events here
+})
\ No newline at end of file
diff --git a/education/education/web_form/student_applicant/student_applicant.json b/education/education/web_form/student_applicant/student_applicant.json
new file mode 100644
index 0000000..c21790c
--- /dev/null
+++ b/education/education/web_form/student_applicant/student_applicant.json
@@ -0,0 +1,498 @@
+{
+ "allow_comments": 0,
+ "allow_delete": 0,
+ "allow_edit": 1,
+ "allow_incomplete": 0,
+ "allow_multiple": 1,
+ "allow_print": 0,
+ "anonymous": 0,
+ "apply_document_permissions": 0,
+ "condition_json": "[]",
+ "creation": "2016-09-22 13:10:10.792735",
+ "doc_type": "Student Applicant",
+ "docstatus": 0,
+ "doctype": "Web Form",
+ "idx": 0,
+ "is_standard": 1,
+ "list_columns": [],
+ "login_required": 1,
+ "max_attachment_size": 0,
+ "modified": "2023-11-18 13:37:05.679995",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "student-applicant",
+ "owner": "Administrator",
+ "published": 1,
+ "route": "student-applicant",
+ "show_attachments": 0,
+ "show_list": 1,
+ "show_sidebar": 1,
+ "success_url": "",
+ "title": "Student Applicant",
+ "web_form_fields": [
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "first_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "First Name",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 1,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "middle_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Middle Name",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "last_name",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Last Name",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "label": "",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 1,
+ "fieldname": "program",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "label": "Program",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Program",
+ "read_only": 0,
+ "reqd": 1,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 1,
+ "fieldname": "academic_year",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "label": "Academic Year",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Academic Year",
+ "read_only": 0,
+ "reqd": 1,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 1,
+ "fieldname": "academic_term",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "label": "Academic Term",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Academic Term",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "label": "",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "student_email_id",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Student Email ID",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 1,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "student_mobile_number",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Student Mobile Number",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "date_of_birth",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "label": "Date of Birth",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "label": "",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 1,
+ "fieldname": "gender",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "label": "Gender",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Gender",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "blood_group",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "label": "Blood Group",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "\nA+\nA-\nB+\nB-\nO+\nO-\nAB+\nAB-",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "default": "",
+ "fieldname": "nationality",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Nationality",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "",
+ "fieldtype": "Page Break",
+ "hidden": 0,
+ "label": "",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "address_tab",
+ "fieldtype": "Page Break",
+ "hidden": 0,
+ "label": "Address",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "address_line_1",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Address Line 1",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "address_line_2",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Address Line 2",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "city",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "City",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "label": "",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "state",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "State",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "pincode",
+ "fieldtype": "Data",
+ "hidden": 0,
+ "label": "Pincode",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "country",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "label": "Country",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Country",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "",
+ "fieldtype": "Page Break",
+ "hidden": 0,
+ "label": "",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "section_break_21",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "label": "Sibling Details",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "siblings",
+ "fieldtype": "Table",
+ "hidden": 0,
+ "label": "Siblings",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Student Sibling",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "section_break_xuzu",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "student_admission",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "label": "Student Admission",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Student Admission",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "student_category",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "label": "Student Category",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Student Category",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "default": "0",
+ "fieldname": "paid",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "label": "Paid",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "column_break_8",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "default": "Today",
+ "fieldname": "application_date",
+ "fieldtype": "Date",
+ "hidden": 0,
+ "label": "Application Date",
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "default": "Applied",
+ "fieldname": "application_status",
+ "fieldtype": "Select",
+ "hidden": 1,
+ "label": "Application Status",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Applied\nApproved\nRejected\nAdmitted",
+ "read_only": 1,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "",
+ "fieldtype": "Section Break",
+ "hidden": 0,
+ "label": "",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "",
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "column_break_lvby",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "max_length": 0,
+ "max_value": 0,
+ "read_only": 0,
+ "reqd": 0,
+ "show_in_filter": 0
+ },
+ {
+ "allow_read_on_all_link_options": 0,
+ "fieldname": "amended_from",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "label": "Amended From",
+ "max_length": 0,
+ "max_value": 0,
+ "options": "Student Applicant",
+ "read_only": 1,
+ "reqd": 0,
+ "show_in_filter": 0
+ }
+ ]
+}
\ No newline at end of file
diff --git a/education/education/web_form/student_applicant/student_applicant.py b/education/education/web_form/student_applicant/student_applicant.py
new file mode 100644
index 0000000..a3508e5
--- /dev/null
+++ b/education/education/web_form/student_applicant/student_applicant.py
@@ -0,0 +1,6 @@
+import xhiveframework
+
+
+def get_context(context):
+ # do your magic here
+ pass
diff --git a/education/education/workspace/education/education.json b/education/education/workspace/education/education.json
new file mode 100644
index 0000000..587aca0
--- /dev/null
+++ b/education/education/workspace/education/education.json
@@ -0,0 +1,758 @@
+{
+ "charts": [
+ {
+ "chart_name": "Program Enrollments",
+ "label": "Program Enrollments"
+ }
+ ],
+ "content": "[{\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Education\",\"col\":12}},{\"type\":\"chart\",\"data\":{\"chart_name\":\"Program Enrollments\",\"col\":12}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"
Your Shortcuts\",\"col\":12}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Student\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Instructor\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Program\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Course\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Fees\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Student Monthly Attendance Sheet\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Course Scheduling Tool\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Student Attendance Tool\",\"col\":3}},{\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"type\":\"spacer\",\"data\":{\"col\":12}},{\"type\":\"header\",\"data\":{\"text\":\"
Reports & Masters\",\"col\":12}},{\"type\":\"card\",\"data\":{\"card_name\":\"Student and Instructor\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Masters\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Content Masters\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Admission\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Fees\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Schedule\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Attendance\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Assessment\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Assessment Reports\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Tools\",\"col\":4}},{\"type\":\"card\",\"data\":{\"card_name\":\"Other Reports\",\"col\":4}}]",
+ "creation": "2020-03-02 17:22:57.066401",
+ "docstatus": 0,
+ "doctype": "Workspace",
+ "for_user": "",
+ "hide_custom": 0,
+ "icon": "education",
+ "idx": 0,
+ "label": "Education",
+ "links": [
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student and Instructor",
+ "link_count": 0,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student",
+ "link_count": 0,
+ "link_to": "Student",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Instructor",
+ "link_count": 0,
+ "link_to": "Instructor",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Guardian",
+ "link_count": 0,
+ "link_to": "Guardian",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Group",
+ "link_count": 0,
+ "link_to": "Student Group",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Log",
+ "link_count": 0,
+ "link_to": "Student Log",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Masters",
+ "link_count": 0,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Program",
+ "link_count": 0,
+ "link_to": "Program",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Course",
+ "link_count": 0,
+ "link_to": "Course",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Topic",
+ "link_count": 0,
+ "link_to": "Topic",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Room",
+ "link_count": 0,
+ "link_to": "Room",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Content Masters",
+ "link_count": 0,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Article",
+ "link_count": 0,
+ "link_to": "Article",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Video",
+ "link_count": 0,
+ "link_to": "Video",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Quiz",
+ "link_count": 0,
+ "link_to": "Quiz",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Settings",
+ "link_count": 0,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Education Settings",
+ "link_count": 0,
+ "link_to": "Education Settings",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Category",
+ "link_count": 0,
+ "link_to": "Student Category",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Batch Name",
+ "link_count": 0,
+ "link_to": "Student Batch Name",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Grading Scale",
+ "link_count": 0,
+ "link_to": "Grading Scale",
+ "link_type": "DocType",
+ "onboard": 1,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Academic Term",
+ "link_count": 0,
+ "link_to": "Academic Term",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Academic Year",
+ "link_count": 0,
+ "link_to": "Academic Year",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Admission",
+ "link_count": 0,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Applicant",
+ "link_count": 0,
+ "link_to": "Student Applicant",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Admission",
+ "link_count": 0,
+ "link_to": "Student Admission",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Program Enrollment",
+ "link_count": 0,
+ "link_to": "Program Enrollment",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Course Enrollment",
+ "link_count": 0,
+ "link_to": "Course Enrollment",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Fees",
+ "link_count": 0,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Fee Structure",
+ "link_count": 0,
+ "link_to": "Fee Structure",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Fee Category",
+ "link_count": 0,
+ "link_to": "Fee Category",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Fee Schedule",
+ "link_count": 0,
+ "link_to": "Fee Schedule",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Fees",
+ "link_count": 0,
+ "link_to": "Fees",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Fees",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Student Fee Collection Report",
+ "link_count": 0,
+ "link_to": "Student Fee Collection",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Fees",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Program wise Fee Collection Report",
+ "link_count": 0,
+ "link_to": "Program wise Fee Collection",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Schedule",
+ "link_count": 0,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Course Schedule",
+ "link_count": 0,
+ "link_to": "Course Schedule",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Course Scheduling Tool",
+ "link_count": 0,
+ "link_to": "Course Scheduling Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Attendance",
+ "link_count": 0,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Attendance",
+ "link_count": 0,
+ "link_to": "Student Attendance",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Leave Application",
+ "link_count": 0,
+ "link_to": "Student Leave Application",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Student Attendance",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Student Monthly Attendance Sheet",
+ "link_count": 0,
+ "link_to": "Student Monthly Attendance Sheet",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Student Attendance",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Absent Student Report",
+ "link_count": 0,
+ "link_to": "Absent Student Report",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Student Attendance",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Student Batch-Wise Attendance",
+ "link_count": 0,
+ "link_to": "Student Batch-Wise Attendance",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Course Enrollment",
+ "link_count": 0,
+ "link_to": "Course Enrollment",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Course Activity",
+ "link_count": 0,
+ "link_to": "Course Activity",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Quiz Activity",
+ "link_count": 0,
+ "link_to": "Quiz Activity",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Assessment",
+ "link_count": 0,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Assessment Plan",
+ "link_count": 0,
+ "link_to": "Assessment Plan",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Assessment Group",
+ "link_count": 0,
+ "link_to": "Assessment Group",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Assessment Result",
+ "link_count": 0,
+ "link_to": "Assessment Result",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Assessment Criteria",
+ "link_count": 0,
+ "link_to": "Assessment Criteria",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Assessment Reports",
+ "link_count": 0,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Assessment Result",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Course wise Assessment Report",
+ "link_count": 0,
+ "link_to": "Course wise Assessment Report",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Assessment Result",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Final Assessment Grades",
+ "link_count": 0,
+ "link_to": "Final Assessment Grades",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "Assessment Plan",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Assessment Plan Status",
+ "link_count": 0,
+ "link_to": "Assessment Plan Status",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Report Generation Tool",
+ "link_count": 0,
+ "link_to": "Student Report Generation Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Tools",
+ "link_count": 0,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Attendance Tool",
+ "link_count": 0,
+ "link_to": "Student Attendance Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Assessment Result Tool",
+ "link_count": 0,
+ "link_to": "Assessment Result Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Student Group Creation Tool",
+ "link_count": 0,
+ "link_to": "Student Group Creation Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Program Enrollment Tool",
+ "link_count": 0,
+ "link_to": "Program Enrollment Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "dependencies": "",
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Course Scheduling Tool",
+ "link_count": 0,
+ "link_to": "Course Scheduling Tool",
+ "link_type": "DocType",
+ "onboard": 0,
+ "type": "Link"
+ },
+ {
+ "hidden": 0,
+ "is_query_report": 0,
+ "label": "Other Reports",
+ "link_count": 0,
+ "onboard": 0,
+ "type": "Card Break"
+ },
+ {
+ "dependencies": "Program Enrollment",
+ "hidden": 0,
+ "is_query_report": 1,
+ "label": "Student and Guardian Contact Details",
+ "link_count": 0,
+ "link_to": "Student and Guardian Contact Details",
+ "link_type": "Report",
+ "onboard": 0,
+ "type": "Link"
+ }
+ ],
+ "modified": "2022-12-12 15:34:55.027081",
+ "modified_by": "Administrator",
+ "module": "Education",
+ "name": "Education",
+ "owner": "Administrator",
+ "parent_page": "",
+ "public": 1,
+ "quick_lists": [],
+ "restrict_to_domain": "",
+ "roles": [],
+ "sequence_id": 9.0,
+ "shortcuts": [
+ {
+ "color": "Grey",
+ "format": "{} Active",
+ "label": "Student",
+ "link_to": "Student",
+ "stats_filter": "{\n \"enabled\": 1\n}",
+ "type": "DocType"
+ },
+ {
+ "color": "Grey",
+ "format": "{} Active",
+ "label": "Instructor",
+ "link_to": "Instructor",
+ "stats_filter": "{\n \"status\": \"Active\"\n}",
+ "type": "DocType"
+ },
+ {
+ "color": "",
+ "format": "",
+ "label": "Program",
+ "link_to": "Program",
+ "stats_filter": "",
+ "type": "DocType"
+ },
+ {
+ "label": "Course",
+ "link_to": "Course",
+ "type": "DocType"
+ },
+ {
+ "color": "Grey",
+ "format": "{} Unpaid",
+ "label": "Fees",
+ "link_to": "Fees",
+ "stats_filter": "{\n \"outstanding_amount\": [\"!=\", 0.0]\n}",
+ "type": "DocType"
+ },
+ {
+ "label": "Student Monthly Attendance Sheet",
+ "link_to": "Student Monthly Attendance Sheet",
+ "type": "Report"
+ },
+ {
+ "label": "Course Scheduling Tool",
+ "link_to": "Course Scheduling Tool",
+ "type": "DocType"
+ },
+ {
+ "label": "Student Attendance Tool",
+ "link_to": "Student Attendance Tool",
+ "type": "DocType"
+ },
+ {
+ "label": "Dashboard",
+ "link_to": "Education",
+ "type": "Dashboard"
+ }
+ ],
+ "title": "Education"
+}
diff --git a/education/hooks.py b/education/hooks.py
new file mode 100644
index 0000000..0e243ac
--- /dev/null
+++ b/education/hooks.py
@@ -0,0 +1,282 @@
+from xhiveframework import _
+
+from . import __version__ as app_version
+
+app_name = "education"
+app_title = "Education"
+app_publisher = "# Copyright (c) 2015, Xhive"
+app_description = "Education"
+app_icon = "octicon octicon-file-directory"
+app_color = "grey"
+app_email = "hello@xhiveframework.io"
+app_license = "GNU GPL V3"
+
+required_apps = ["xhiveerp"]
+
+# Includes in
+# ------------------
+
+# include js, css files in header of desk.html
+# app_include_css = "/assets/education/css/education.css"
+# app_include_js = "/assets/education/js/education.js"
+app_include_js = "education.bundle.js"
+
+# include js, css files in header of web template
+# web_include_css = "/assets/education/css/education.css"
+# web_include_js = "/assets/education/js/education.js"
+
+# include custom scss in every website theme (without file extension ".scss")
+# website_theme_scss = "education/public/scss/website"
+
+# website
+update_website_context = []
+
+website_generators = ["Student Admission"]
+
+website_route_rules = [
+ {"from_route": "/admissions", "to_route": "Student Admission"},
+]
+
+treeviews = ["Assessment Group"]
+
+calendars = [
+ "Course Schedule",
+]
+
+standard_portal_menu_items = [
+ {"title": _("Fees"), "route": "/fees", "reference_doctype": "Fees", "role": "Student"},
+ {
+ "title": _("Admission"),
+ "route": "/admissions",
+ "reference_doctype": "Student Admission",
+ "role": "Student",
+ },
+]
+
+default_roles = [
+ {"role": "Student", "doctype": "Student", "email_field": "student_email_id"},
+]
+
+accounting_dimension_doctypes = ["Fee Schedule", "Fee Structure", "Fees"]
+
+global_search_doctypes = {
+ "Education": [
+ {"doctype": "Article", "index": 1},
+ {"doctype": "Video", "index": 2},
+ {"doctype": "Topic", "index": 3},
+ {"doctype": "Course", "index": 4},
+ {"doctype": "Program", "index": 5},
+ {"doctype": "Quiz", "index": 6},
+ {"doctype": "Question", "index": 7},
+ {"doctype": "Fee Schedule", "index": 8},
+ {"doctype": "Fee Structure", "index": 9},
+ {"doctype": "Fees", "index": 10},
+ {"doctype": "Student Group", "index": 11},
+ {"doctype": "Student", "index": 12},
+ {"doctype": "Instructor", "index": 13},
+ {"doctype": "Course Activity", "index": 14},
+ {"doctype": "Quiz Activity", "index": 15},
+ {"doctype": "Course Enrollment", "index": 16},
+ {"doctype": "Program Enrollment", "index": 17},
+ {"doctype": "Student Language", "index": 18},
+ {"doctype": "Student Applicant", "index": 19},
+ {"doctype": "Assessment Result", "index": 20},
+ {"doctype": "Assessment Plan", "index": 21},
+ {"doctype": "Grading Scale", "index": 22},
+ {"doctype": "Guardian", "index": 23},
+ {"doctype": "Student Leave Application", "index": 24},
+ {"doctype": "Student Log", "index": 25},
+ {"doctype": "Room", "index": 26},
+ {"doctype": "Course Schedule", "index": 27},
+ {"doctype": "Student Attendance", "index": 28},
+ {"doctype": "Announcement", "index": 29},
+ {"doctype": "Student Category", "index": 30},
+ {"doctype": "Assessment Group", "index": 31},
+ {"doctype": "Student Batch Name", "index": 32},
+ {"doctype": "Assessment Criteria", "index": 33},
+ {"doctype": "Academic Year", "index": 34},
+ {"doctype": "Academic Term", "index": 35},
+ {"doctype": "School House", "index": 36},
+ {"doctype": "Student Admission", "index": 37},
+ {"doctype": "Fee Category", "index": 38},
+ {"doctype": "Assessment Code", "index": 39},
+ {"doctype": "Discussion", "index": 40},
+ ]
+}
+
+# fixed route to education setup
+domains = {
+ "Education": "education.education.setup",
+}
+# include js, css files in header of web form
+# webform_include_js = {"doctype": "public/js/doctype.js"}
+# webform_include_css = {"doctype": "public/css/doctype.css"}
+
+# include js in page
+# page_js = {"page" : "public/js/file.js"}
+
+# include js in doctype views
+# doctype_js = {"doctype" : "public/js/doctype.js"}
+# doctype_list_js = {"doctype" : "public/js/doctype_list.js"}
+# doctype_tree_js = {"doctype" : "public/js/doctype_tree.js"}
+# doctype_calendar_js = {"doctype" : "public/js/doctype_calendar.js"}
+
+# Home Pages
+# ----------
+
+# application home page (will override Website Settings)
+# home_page = "login"
+
+# website user home page (by Role)
+# role_home_page = {
+# "Role": "home_page"
+# }
+
+# Generators
+# ----------
+
+# automatically create page for each record of this doctype
+# website_generators = ["Web Page"]
+
+# Jinja
+# ----------
+
+# add methods and filters to jinja environment
+# jinja = {
+# "methods": "education.utils.jinja_methods",
+# "filters": "education.utils.jinja_filters"
+# }
+
+# Installation
+# ------------
+
+# before_install = "education.install.before_install"
+after_install = "education.install.after_install"
+
+# Uninstallation
+# ------------
+
+# before_uninstall = "education.uninstall.before_uninstall"
+# after_uninstall = "education.uninstall.after_uninstall"
+
+# Desk Notifications
+# ------------------
+# See xhiveframework.core.notifications.get_notification_config
+
+# notification_config = "education.notifications.get_notification_config"
+
+# Permissions
+# -----------
+# Permissions evaluated in scripted ways
+
+# permission_query_conditions = {
+# "Event": "xhiveframework.desk.doctype.event.event.get_permission_query_conditions",
+# }
+#
+# has_permission = {
+# "Event": "xhiveframework.desk.doctype.event.event.has_permission",
+# }
+
+# DocType Class
+# ---------------
+# Override standard doctype classes
+
+# override_doctype_class = {
+# "ToDo": "custom_app.overrides.CustomToDo"
+# }
+
+# Document Events
+# ---------------
+# Hook on document methods and events
+
+# doc_events = {
+# "*": {
+# "on_update": "method",
+# "on_cancel": "method",
+# "on_trash": "method"
+# }
+# }
+
+# Scheduled Tasks
+# ---------------
+
+# scheduler_events = {
+# "all": [
+# "education.tasks.all"
+# ],
+# "daily": [
+# "education.tasks.daily"
+# ],
+# "hourly": [
+# "education.tasks.hourly"
+# ],
+# "weekly": [
+# "education.tasks.weekly"
+# ],
+# "monthly": [
+# "education.tasks.monthly"
+# ],
+# }
+
+# Testing
+# -------
+
+# before_tests = "education.install.before_tests"
+
+# Overriding Methods
+# ------------------------------
+#
+# override_whitelisted_methods = {
+# "xhiveframework.desk.doctype.event.event.get_events": "education.event.get_events"
+# }
+#
+# each overriding function accepts a `data` argument;
+# generated from the base implementation of the doctype dashboard,
+# along with any modifications made in other XhiveFramework apps
+# override_doctype_dashboards = {
+# "Task": "education.task.get_dashboard_data"
+# }
+
+# exempt linked doctypes from being automatically cancelled
+#
+# auto_cancel_exempted_doctypes = ["Auto Repeat"]
+
+
+# User Data Protection
+# --------------------
+
+# user_data_fields = [
+# {
+# "doctype": "{doctype_1}",
+# "filter_by": "{filter_by}",
+# "redact_fields": ["{field_1}", "{field_2}"],
+# "partial": 1,
+# },
+# {
+# "doctype": "{doctype_2}",
+# "filter_by": "{filter_by}",
+# "partial": 1,
+# },
+# {
+# "doctype": "{doctype_3}",
+# "strict": False,
+# },
+# {
+# "doctype": "{doctype_4}"
+# }
+# ]
+
+# Authentication and authorization
+# --------------------------------
+
+# auth_hooks = [
+# "education.auth.validate"
+# ]
+
+# Translation
+# --------------------------------
+
+# Make link fields search translated document names for these DocTypes
+# Recommended only for DocTypes which have limited documents with untranslated names
+# For example: Role, Gender, etc.
+# translated_search_doctypes = []
diff --git a/education/install.py b/education/install.py
new file mode 100644
index 0000000..2f2a6ed
--- /dev/null
+++ b/education/install.py
@@ -0,0 +1,34 @@
+import xhiveframework
+
+
+def after_install():
+ setup_fixtures()
+ create_student_role()
+ create_parent_assessment_group()
+
+
+def setup_fixtures():
+ records = [
+ {"doctype": "Party Type", "party_type": "Student", "account_type": "Receivable"}
+ ]
+
+ for record in records:
+ if not xhiveframework.db.exists("Party Type", record.get("party_type")):
+ doc = xhiveframework.get_doc(record)
+ doc.insert()
+
+
+def create_parent_assessment_group():
+ if not xhiveframework.db.exists("Assessment Group", "All Assessment Groups"):
+ xhiveframework.get_doc(
+ {
+ "doctype": "Assessment Group",
+ "assessment_group_name": "All Assessment Groups",
+ "is_group": 1,
+ }
+ ).insert(ignore_mandatory=True)
+
+
+def create_student_role():
+ if not xhiveframework.db.exists("Role", "Student"):
+ xhiveframework.get_doc({"doctype": "Role", "role_name": "Student", "desk_access": 0}).save()
diff --git a/education/modules.txt b/education/modules.txt
new file mode 100644
index 0000000..937e7cf
--- /dev/null
+++ b/education/modules.txt
@@ -0,0 +1 @@
+Education
\ No newline at end of file
diff --git a/education/patches.txt b/education/patches.txt
new file mode 100644
index 0000000..b262a92
--- /dev/null
+++ b/education/patches.txt
@@ -0,0 +1,9 @@
+[pre_model_sync]
+education.patches.v14_0.create_student_party_type
+
+[post_model_sync]
+education.patches.v14_0.create_parent_assessment_group #01-01-2022
+education.patches.v14_0.lms_deprecation_message #22-12-2022
+education.patches.v14_0.student_name
+education.patches.v14_0.delete_lms_user_role
+education.patches.v15_0.fees_student_email
\ No newline at end of file
diff --git a/education/patches/v14_0/create_parent_assessment_group.py b/education/patches/v14_0/create_parent_assessment_group.py
new file mode 100644
index 0000000..d803724
--- /dev/null
+++ b/education/patches/v14_0/create_parent_assessment_group.py
@@ -0,0 +1,10 @@
+import xhiveframework
+
+from education.install import create_parent_assessment_group
+
+
+def execute():
+ create_parent_assessment_group()
+
+ if xhiveframework.db.exists("Assessment Group", "undefined"):
+ xhiveframework.delete_doc("Assessment Group", "undefined")
diff --git a/education/patches/v14_0/create_student_party_type.py b/education/patches/v14_0/create_student_party_type.py
new file mode 100644
index 0000000..ee140f3
--- /dev/null
+++ b/education/patches/v14_0/create_student_party_type.py
@@ -0,0 +1,9 @@
+import xhiveframework
+
+
+def execute():
+ if not xhiveframework.db.exists("Party Type", "Student"):
+ doc = xhiveframework.get_doc(
+ {"doctype": "Party Type", "party_type": "Student", "account_type": "Receivable"}
+ )
+ doc.insert()
diff --git a/education/patches/v14_0/delete_lms_user_role.py b/education/patches/v14_0/delete_lms_user_role.py
new file mode 100644
index 0000000..63c6395
--- /dev/null
+++ b/education/patches/v14_0/delete_lms_user_role.py
@@ -0,0 +1,6 @@
+import xhiveframework
+
+
+def execute():
+ if xhiveframework.db.exists("Role", "LMS User"):
+ xhiveframework.db.delete("Role", "LMS User")
diff --git a/education/patches/v14_0/lms_deprecation_message.py b/education/patches/v14_0/lms_deprecation_message.py
new file mode 100644
index 0000000..1e69033
--- /dev/null
+++ b/education/patches/v14_0/lms_deprecation_message.py
@@ -0,0 +1,14 @@
+import click
+import xhiveframework
+
+
+def execute():
+
+ click.secho(
+ "LMS Module has been removed from the Education App. "
+ "There is a new app for it called the XhiveFramework LMS App. "
+ "You can install the app from GitHub or XhiveFramework Cloud Marketplace.\n"
+ "https://github.com/xhiveframework/lms\n"
+ "https://xhiveframeworkcloud.com/marketplace/apps/lms",
+ fg="yellow",
+ )
diff --git a/education/patches/v14_0/student_name.py b/education/patches/v14_0/student_name.py
new file mode 100644
index 0000000..eaee3f5
--- /dev/null
+++ b/education/patches/v14_0/student_name.py
@@ -0,0 +1,12 @@
+import xhiveframework
+
+
+def execute():
+ students = xhiveframework.get_all(
+ "Student", fields=["name", "first_name", "middle_name", "last_name"]
+ )
+ for student in students:
+ student_name = " ".join(
+ filter(None, [student.first_name, student.middle_name, student.last_name])
+ )
+ xhiveframework.db.set_value("Student", student.name, "student_name", student_name)
diff --git a/education/patches/v15_0/fees_student_email.py b/education/patches/v15_0/fees_student_email.py
new file mode 100644
index 0000000..35ffc6d
--- /dev/null
+++ b/education/patches/v15_0/fees_student_email.py
@@ -0,0 +1,7 @@
+import xhiveframework
+
+
+def execute():
+ student_emails = xhiveframework.db.get_all("Fees", fields=["name", "student_email"])
+ for email in student_emails:
+ xhiveframework.db.set_value("Fees", email.name, "contact_email", email.student_email)
diff --git a/education/public/.gitkeep b/education/public/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/education/public/js/assessment_result_tool.html b/education/public/js/assessment_result_tool.html
new file mode 100644
index 0000000..f7d1ab3
--- /dev/null
+++ b/education/public/js/assessment_result_tool.html
@@ -0,0 +1,72 @@
+
diff --git a/education/public/js/education.bundle.js b/education/public/js/education.bundle.js
new file mode 100644
index 0000000..6af5641
--- /dev/null
+++ b/education/public/js/education.bundle.js
@@ -0,0 +1 @@
+import "./assessment_result_tool.html";
diff --git a/education/templates/__init__.py b/education/templates/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/templates/generators/student_admission.html b/education/templates/generators/student_admission.html
new file mode 100644
index 0000000..8cc58a0
--- /dev/null
+++ b/education/templates/generators/student_admission.html
@@ -0,0 +1,27 @@
+
+{% extends "templates/web.html" %}
+
+{% block breadcrumbs %}
+ {% include "templates/includes/breadcrumbs.html" %}
+{% endblock %}
+
+{% block header %}
+
+
{{ title }}
+{% endblock %}
+
+{% block page_content %}
+
+{%- if introduction -%}
+
{{ introduction }}
+{% endif %}
+
+{%- if doc.enable_admission_application -%}
+
+
+ {{ _("Apply Now") }}
+
+{% endif %}
+
+{% endblock %}
diff --git a/education/templates/includes/assessment/assessment_row.html b/education/templates/includes/assessment/assessment_row.html
new file mode 100644
index 0000000..a33ccff
--- /dev/null
+++ b/education/templates/includes/assessment/assessment_row.html
@@ -0,0 +1,19 @@
+
+
+
+ {{ doc.course }}
+
+
+ {{ doc.room }}
+
+
+ {{doc.schedule_date }}
+
+
+ {{ doc.from_time }}
+
+
+ {{ doc.to_time }}
+
+
+
diff --git a/education/templates/includes/course/course_row.html b/education/templates/includes/course/course_row.html
new file mode 100644
index 0000000..fddfc3c
--- /dev/null
+++ b/education/templates/includes/course/course_row.html
@@ -0,0 +1,18 @@
+
diff --git a/education/templates/includes/course/macros.html b/education/templates/includes/course/macros.html
new file mode 100644
index 0000000..334b5ea
--- /dev/null
+++ b/education/templates/includes/course/macros.html
@@ -0,0 +1 @@
+{% macro back_link(doc) %}&back-to=/courses?course={{ doc.name }}&back-to-title={{ doc.course_name }}{% endmacro %}
diff --git a/education/templates/pages/__init__.py b/education/templates/pages/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/education/www/__init__.py b/education/www/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/license.txt b/license.txt
new file mode 100644
index 0000000..beca179
--- /dev/null
+++ b/license.txt
@@ -0,0 +1 @@
+License: GNU GPL V3
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..f835b96
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1 @@
+# xhiveframework -- https://github.com/xhiveframework/xhiveframework is installed via 'bench init'
\ No newline at end of file
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..e1a6624
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,19 @@
+from setuptools import setup, find_packages
+
+with open("requirements.txt") as f:
+ install_requires = f.read().strip().split("\n")
+
+# get version from __version__ variable in education/__init__.py
+from education import __version__ as version
+
+setup(
+ name="education",
+ version=version,
+ description="Education",
+ author="XhiveFramework Technologies Pvt. Ltd.",
+ author_email="hello@xhiveframework.io",
+ packages=find_packages(),
+ zip_safe=False,
+ include_package_data=True,
+ install_requires=install_requires,
+)