From d9bc5598b651170bd4768e0f27701cb1d06f8c7f Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Thu, 17 Nov 2016 15:35:54 +0530 Subject: [PATCH] Added ability to mark attendance against a Student Batch --- erpnext/config/schools.py | 4 + erpnext/schools/api.py | 32 ++- .../doctype/assessment/assessment.json | 33 ++- .../schools/doctype/assessment/assessment.py | 92 ++++---- .../course_schedule/course_schedule.js | 2 +- .../course_schedule/course_schedule.json | 71 +++++-- .../course_schedule/course_schedule.py | 38 +++- .../scheduling_tool/scheduling_tool.js | 1 + .../scheduling_tool/scheduling_tool.json | 190 ++++++++++++----- .../scheduling_tool/scheduling_tool.py | 13 +- .../student_attendance/student_attendance.js | 3 + .../student_attendance.json | 81 +++++-- .../student_attendance/student_attendance.py | 28 ++- .../student_batch_attendance_tool/__init__.py | 0 .../student_batch_attendance_tool.js | 128 +++++++++++ .../student_batch_attendance_tool.json | 201 ++++++++++++++++++ .../student_batch_attendance_tool.py | 10 + 17 files changed, 780 insertions(+), 147 deletions(-) create mode 100644 erpnext/schools/doctype/student_batch_attendance_tool/__init__.py create mode 100644 erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.js create mode 100644 erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.json create mode 100644 erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.py diff --git a/erpnext/config/schools.py b/erpnext/config/schools.py index 6acf081b3f..41a8e71073 100644 --- a/erpnext/config/schools.py +++ b/erpnext/config/schools.py @@ -71,6 +71,10 @@ def get_data(): "type": "doctype", "name": "Assessment Group" }, + { + "type": "doctype", + "name": "Student Batch Attendance Tool" + }, { "type": "doctype", "name": "Scheduling Tool" diff --git a/erpnext/schools/api.py b/erpnext/schools/api.py index 6011158633..dea8515159 100644 --- a/erpnext/schools/api.py +++ b/erpnext/schools/api.py @@ -30,33 +30,40 @@ def enroll_student(source_name): return program_enrollment @frappe.whitelist() -def check_attendance_records_exist(course_schedule): - """Check if Attendance Records are made against the specified Course Schedule. +def check_attendance_records_exist(course_schedule=None, student_batch=None, date=None): + """Check if Attendance Records are made against the specified Course Schedule or Student Batch for given date. :param course_schedule: Course Schedule. + :param student_batch: Student Batch. + :param date: Date. """ - return frappe.get_list("Student Attendance", filters={"course_schedule": course_schedule}) + if course_schedule: + return frappe.get_list("Student Attendance", filters={"course_schedule": course_schedule}) + else: + return frappe.get_list("Student Attendance", filters={"student_batch": student_batch, "date": date}) @frappe.whitelist() -def mark_attendance(students_present, students_absent, course_schedule): +def mark_attendance(students_present, students_absent, course_schedule=None, student_batch=None, date=None): """Creates Multiple Attendance Records. :param students_present: Students Present JSON. :param students_absent: Students Absent JSON. :param course_schedule: Course Schedule. + :param student_batch: Student Batch. + :param date: Date. """ present = json.loads(students_present) absent = json.loads(students_absent) for d in present: - make_attendance_records(d["student"], d["student_name"], course_schedule, "Present") + make_attendance_records(d["student"], d["student_name"], "Present", course_schedule, student_batch, date) for d in absent: - make_attendance_records(d["student"], d["student_name"], course_schedule, "Absent") + make_attendance_records(d["student"], d["student_name"], "Absent", course_schedule, student_batch, date) frappe.msgprint(_("Attendance has been marked successfully.")) -def make_attendance_records(student, student_name, course_schedule, status): +def make_attendance_records(student, student_name, status, course_schedule=None, student_batch=None, date=None): """Creates Attendance Record. :param student: Student. @@ -68,10 +75,21 @@ def make_attendance_records(student, student_name, course_schedule, status): student_attendance.student = student student_attendance.student_name = student_name student_attendance.course_schedule = course_schedule + student_attendance.student_batch = student_batch + student_attendance.date = date student_attendance.status = status student_attendance.submit() frappe.db.commit() +@frappe.whitelist() +def get_student_batch_students(student_batch): + """Returns List of student, student_name in Student Batch. + + :param student_batch: Student Batch. + """ + students = frappe.get_list("Student Batch Student", fields=["student", "student_name"] , filters={"parent": student_batch}, order_by= "idx") + return students + @frappe.whitelist() def get_student_group_students(student_group): """Returns List of student, student_name in Student Group. diff --git a/erpnext/schools/doctype/assessment/assessment.json b/erpnext/schools/doctype/assessment/assessment.json index 9f1349c17b..845f2f6500 100644 --- a/erpnext/schools/doctype/assessment/assessment.json +++ b/erpnext/schools/doctype/assessment/assessment.json @@ -92,7 +92,36 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 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_list_view": 0, + "in_standard_filter": 0, + "label": "Student Batch", + "length": 0, + "no_copy": 0, + "options": "Student Batch", + "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 @@ -593,7 +622,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2016-11-07 05:47:47.529783", + "modified": "2016-11-16 13:05:54.953750", "modified_by": "Administrator", "module": "Schools", "name": "Assessment", diff --git a/erpnext/schools/doctype/assessment/assessment.py b/erpnext/schools/doctype/assessment/assessment.py index de6a653967..cb307cb7f4 100644 --- a/erpnext/schools/doctype/assessment/assessment.py +++ b/erpnext/schools/doctype/assessment/assessment.py @@ -8,56 +8,66 @@ import frappe from frappe import _ class Assessment(Document): - def validate(self): - self.validate_overlap() - - def validate_overlap(self): - """Validates overlap for Student Group, Supervisor, Room""" + def validate(self): + self.validate_overlap() + + def validate_overlap(self): + """Validates overlap for Student Group/Student Batch, Instructor, Room""" + + from erpnext.schools.utils import validate_overlap_for - from erpnext.schools.utils import validate_overlap_for + #Validate overlapping course schedules. + if self.student_batch: + validate_overlap_for(self, "Course Schedule", "student_batch") - validate_overlap_for(self, "Assessment", "student_group") - validate_overlap_for(self, "Course Schedule", "student_group" ) - - if self.room: - validate_overlap_for(self, "Assessment", "room") - validate_overlap_for(self, "Course Schedule", "room") + if self.student_group: + validate_overlap_for(self, "Course Schedule", "student_group") + + validate_overlap_for(self, "Course Schedule", "instructor") + validate_overlap_for(self, "Course Schedule", "room") + + #validate overlapping assessment schedules. + if self.student_batch: + validate_overlap_for(self, "Assessment", "student_batch") + + if self.student_group: + validate_overlap_for(self, "Assessment", "student_group") + + validate_overlap_for(self, "Assessment", "room") + validate_overlap_for(self, "Assessment", "supervisor", self.instructor) - if self.supervisor: - validate_overlap_for(self, "Assessment", "supervisor") - validate_overlap_for(self, "Course Schedule", "instructor", self.supervisor) def get_assessment_list(doctype, txt, filters, limit_start, limit_page_length=20): - user = frappe.session.user - student = frappe.db.sql("select name from `tabStudent` where student_email_id= %s", user) - if student: - return frappe. db.sql('''select course, schedule_date, from_time, to_time, sgs.name from `tabAssessment` as assessment, - `tabStudent Group Student` as sgs where assessment.student_group = sgs.parent and sgs.student = %s and assessment.docstatus=1 - order by assessment.name asc limit {0} , {1}''' - .format(limit_start, limit_page_length), student, as_dict = True) + user = frappe.session.user + student = frappe.db.sql("select name from `tabStudent` where student_email_id= %s", user) + if student: + return frappe. db.sql('''select course, schedule_date, from_time, to_time, sgs.name from `tabAssessment` as assessment, + `tabStudent Group Student` as sgs where assessment.student_group = sgs.parent and sgs.student = %s and assessment.docstatus=1 + order by assessment.name asc limit {0} , {1}''' + .format(limit_start, limit_page_length), student, as_dict = True) def get_list_context(context=None): - return { - "show_sidebar": True, - 'no_breadcrumbs': True, - "title": _("Assessment Schedule"), - "get_list": get_assessment_list, - "row_template": "templates/includes/assessment/assessment_row.html" - } + return { + "show_sidebar": True, + 'no_breadcrumbs': True, + "title": _("Assessment Schedule"), + "get_list": get_assessment_list, + "row_template": "templates/includes/assessment/assessment_row.html" + } @frappe.whitelist() def get_grade(grading_structure, result): - grade = frappe.db.sql("""select gi.from_score, gi.to_score, gi.grade_code, gi.grade_description - from `tabGrading Structure` as gs, `tabGrade Interval` as gi - where gs.name = gi.parent and gs.name = %(grading_structure)s and gi.from_score <= %(result)s - and gi.to_score >= %(result)s""".format(), - { - "grading_structure":grading_structure, - "result": result - }, - as_dict=True) - - return grade[0].grade_code if grade else "" + grade = frappe.db.sql("""select gi.from_score, gi.to_score, gi.grade_code, gi.grade_description + from `tabGrading Structure` as gs, `tabGrade Interval` as gi + where gs.name = gi.parent and gs.name = %(grading_structure)s and gi.from_score <= %(result)s + and gi.to_score >= %(result)s""".format(), + { + "grading_structure":grading_structure, + "result": result + }, + as_dict=True) + + return grade[0].grade_code if grade else "" def validate_grade(score, grade): - pass \ No newline at end of file + pass \ No newline at end of file diff --git a/erpnext/schools/doctype/course_schedule/course_schedule.js b/erpnext/schools/doctype/course_schedule/course_schedule.js index 2defbd5df6..ab34ae96c1 100644 --- a/erpnext/schools/doctype/course_schedule/course_schedule.js +++ b/erpnext/schools/doctype/course_schedule/course_schedule.js @@ -12,7 +12,7 @@ frappe.ui.form.on("Course Schedule" ,{ }, refresh :function(frm) { - if(!frm.doc.__islocal) { + if(!frm.doc.__islocal && frm.doc.student_group) { frappe.call({ method: "erpnext.schools.api.check_attendance_records_exist", args: { diff --git a/erpnext/schools/doctype/course_schedule/course_schedule.json b/erpnext/schools/doctype/course_schedule/course_schedule.json index eda1ec7027..4a4b2d3a4b 100644 --- a/erpnext/schools/doctype/course_schedule/course_schedule.json +++ b/erpnext/schools/doctype/course_schedule/course_schedule.json @@ -2,7 +2,7 @@ "allow_copy": 0, "allow_import": 1, "allow_rename": 0, - "autoname": "naming_series", + "autoname": "naming_series:", "beta": 0, "creation": "2015-09-09 16:34:04.960369", "custom": 0, @@ -12,6 +12,35 @@ "editable_grid": 0, "engine": "InnoDB", "fields": [ + { + "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_list_view": 0, + "in_standard_filter": 0, + "label": "Student Batch", + "length": 0, + "no_copy": 0, + "options": "Student Batch", + "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_on_submit": 0, "bold": 0, @@ -36,7 +65,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -75,24 +104,23 @@ "bold": 0, "collapsible": 0, "columns": 0, - "default": "SH", - "fieldname": "naming_series", - "fieldtype": "Select", + "fieldname": "instructor_name", + "fieldtype": "Read Only", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Naming Series", + "label": "Instructor Name", "length": 0, "no_copy": 0, - "options": "SH", + "options": "instructor.Instructor_name", "permlevel": 0, "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 0, + "read_only": 1, "remember_last_selected_value": 0, "report_hide": 0, "reqd": 0, @@ -132,26 +160,27 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "course", - "fieldtype": "Read Only", + "default": "SH", + "fieldname": "naming_series", + "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Course", + "label": "Naming Series", "length": 0, "no_copy": 0, - "options": "student_group.course", + "options": "SH", "permlevel": 0, "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -161,26 +190,26 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "instructor_name", - "fieldtype": "Read Only", + "fieldname": "course", + "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Instructor Name", + "label": "Course", "length": 0, "no_copy": 0, - "options": "instructor.Instructor_name", + "options": "Course", "permlevel": 0, "precision": "", "print_hide": 0, "print_hide_if_no_value": 0, - "read_only": 1, + "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 0, + "reqd": 1, "search_index": 0, "set_only_once": 0, "unique": 0 @@ -449,7 +478,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2016-11-07 05:51:34.493014", + "modified": "2016-11-16 16:38:00.454295", "modified_by": "Administrator", "module": "Schools", "name": "Course Schedule", diff --git a/erpnext/schools/doctype/course_schedule/course_schedule.py b/erpnext/schools/doctype/course_schedule/course_schedule.py index 11f3894d8c..ec30c62140 100644 --- a/erpnext/schools/doctype/course_schedule/course_schedule.py +++ b/erpnext/schools/doctype/course_schedule/course_schedule.py @@ -4,34 +4,62 @@ from __future__ import unicode_literals import frappe +from frappe import _ from frappe.model.document import Document class CourseSchedule(Document): def validate(self): self.instructor_name = frappe.db.get_value("Instructor", self.instructor, "instructor_name") self.set_title() + self.validate_mandatory() + self.validate_course() + self.set_student_batch() self.validate_date() self.validate_overlap() - + def set_title(self): """Set document Title""" self.title = self.course + " by " + (self.instructor_name if self.instructor_name else self.instructor) + def validate_mandatory(self): + if not (self.student_batch or self.student_group): + frappe.throw(_("""Student Batch or Student Group is mandatory""")) + + def validate_course(self): + if self.student_group: + self.course= frappe.db.get_value("Student Group", self.student_group, "course") + + def set_student_batch(self): + if self.student_group: + self.student_batch = frappe.db.get_value("Student Group", self.student_group, "student_batch") + def validate_date(self): """Validates if from_time is greater than to_time""" if self.from_time > self.to_time: - frappe.throw("From Time cannot be greater than To Time.") + frappe.throw(_("From Time cannot be greater than To Time.")) def validate_overlap(self): - """Validates overlap for Student Group, Instructor, Room""" + """Validates overlap for Student Group/Student Batch, Instructor, Room""" from erpnext.schools.utils import validate_overlap_for - validate_overlap_for(self, "Course Schedule", "student_group" ) + #Validate overlapping course schedules. + if self.student_batch: + validate_overlap_for(self, "Course Schedule", "student_batch") + + if self.student_group: + validate_overlap_for(self, "Course Schedule", "student_group") + validate_overlap_for(self, "Course Schedule", "instructor") validate_overlap_for(self, "Course Schedule", "room") - validate_overlap_for(self, "Assessment", "student_group") + #validate overlapping assessment schedules. + if self.student_batch: + validate_overlap_for(self, "Assessment", "student_batch") + + if self.student_group: + validate_overlap_for(self, "Assessment", "student_group") + validate_overlap_for(self, "Assessment", "room") validate_overlap_for(self, "Assessment", "supervisor", self.instructor) diff --git a/erpnext/schools/doctype/scheduling_tool/scheduling_tool.js b/erpnext/schools/doctype/scheduling_tool/scheduling_tool.js index 7109771a6e..50113752df 100644 --- a/erpnext/schools/doctype/scheduling_tool/scheduling_tool.js +++ b/erpnext/schools/doctype/scheduling_tool/scheduling_tool.js @@ -1,4 +1,5 @@ cur_frm.add_fetch("student_group", "program", "program"); +cur_frm.add_fetch("student_group", "student_batch", "student_batch"); cur_frm.add_fetch("student_group", "course", "course"); cur_frm.add_fetch("student_group", "academic_year", "academic_year"); cur_frm.add_fetch("student_group", "academic_term", "academic_term"); diff --git a/erpnext/schools/doctype/scheduling_tool/scheduling_tool.json b/erpnext/schools/doctype/scheduling_tool/scheduling_tool.json index 41a7b94e88..cf2c1a3d11 100644 --- a/erpnext/schools/doctype/scheduling_tool/scheduling_tool.json +++ b/erpnext/schools/doctype/scheduling_tool/scheduling_tool.json @@ -9,11 +9,42 @@ "doctype": "DocType", "document_type": "Setup", "editable_grid": 0, + "engine": "InnoDB", "fields": [ { "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_list_view": 0, + "in_standard_filter": 0, + "label": "Student Batch", + "length": 0, + "no_copy": 0, + "options": "Student Batch", + "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_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, "fieldname": "student_group", "fieldtype": "Link", "hidden": 0, @@ -21,6 +52,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Student Group", "length": 0, "no_copy": 0, @@ -30,6 +62,36 @@ "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_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_list_view": 0, + "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": 1, "search_index": 0, @@ -40,6 +102,34 @@ "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_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_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, "fieldname": "academic_year", "fieldtype": "Link", "hidden": 0, @@ -47,6 +137,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Academic Year", "length": 0, "no_copy": 0, @@ -56,6 +147,7 @@ "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, @@ -66,6 +158,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "academic_term", "fieldtype": "Link", "hidden": 0, @@ -73,6 +166,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Academic Term", "length": 0, "no_copy": 0, @@ -82,6 +176,7 @@ "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, @@ -92,30 +187,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "column_break_3", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, + "columns": 0, "fieldname": "program", "fieldtype": "Link", "hidden": 0, @@ -123,6 +195,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Program", "length": 0, "no_copy": 0, @@ -132,6 +205,7 @@ "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, @@ -142,32 +216,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, - "fieldname": "course", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_list_view": 0, - "label": "Course", - "length": 0, - "no_copy": 0, - "options": "Course", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, + "columns": 0, "fieldname": "section_break_6", "fieldtype": "Section Break", "hidden": 0, @@ -175,6 +224,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "length": 0, "no_copy": 0, "permlevel": 0, @@ -182,6 +232,7 @@ "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, @@ -192,6 +243,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "room", "fieldtype": "Link", "hidden": 0, @@ -199,6 +251,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Room", "length": 0, "no_copy": 0, @@ -208,6 +261,7 @@ "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, @@ -218,6 +272,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "column_break_9", "fieldtype": "Column Break", "hidden": 0, @@ -225,6 +280,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "length": 0, "no_copy": 0, "permlevel": 0, @@ -232,6 +288,7 @@ "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, @@ -242,6 +299,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "instructor", "fieldtype": "Link", "hidden": 0, @@ -249,6 +307,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Instructor", "length": 0, "no_copy": 0, @@ -258,6 +317,7 @@ "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, @@ -268,6 +328,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "instructor_name", "fieldtype": "Read Only", "hidden": 0, @@ -275,6 +336,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Instructor Name", "length": 0, "no_copy": 0, @@ -284,6 +346,7 @@ "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, @@ -294,6 +357,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "section_break_7", "fieldtype": "Section Break", "hidden": 0, @@ -301,6 +365,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "length": 0, "no_copy": 0, "permlevel": 0, @@ -308,6 +373,7 @@ "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, @@ -318,6 +384,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "default": "", "fieldname": "from_time", "fieldtype": "Time", @@ -326,6 +393,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "From Time", "length": 0, "no_copy": 0, @@ -334,6 +402,7 @@ "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, @@ -344,6 +413,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "default": "", "fieldname": "course_start_date", "fieldtype": "Date", @@ -352,6 +422,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Course Start Date", "length": 0, "no_copy": 0, @@ -361,6 +432,7 @@ "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, @@ -371,6 +443,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "day", "fieldtype": "Select", "hidden": 0, @@ -378,6 +451,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Day", "length": 0, "no_copy": 0, @@ -387,6 +461,7 @@ "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, @@ -397,6 +472,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "rechedule", "fieldtype": "Check", "hidden": 0, @@ -404,6 +480,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Rechedule", "length": 0, "no_copy": 0, @@ -412,6 +489,7 @@ "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, @@ -422,6 +500,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "column_break_15", "fieldtype": "Column Break", "hidden": 0, @@ -429,6 +508,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "length": 0, "no_copy": 0, "permlevel": 0, @@ -436,6 +516,7 @@ "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, @@ -446,6 +527,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "to_time", "fieldtype": "Time", "hidden": 0, @@ -453,6 +535,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "To TIme", "length": 0, "no_copy": 0, @@ -461,6 +544,7 @@ "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, @@ -471,6 +555,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "default": "", "fieldname": "course_end_date", "fieldtype": "Date", @@ -479,6 +564,7 @@ "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, + "in_standard_filter": 0, "label": "Course End Date", "length": 0, "no_copy": 0, @@ -487,6 +573,7 @@ "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, @@ -505,7 +592,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2016-07-25 01:24:48.220756", + "modified": "2016-11-16 16:03:41.854229", "modified_by": "Administrator", "module": "Schools", "name": "Scheduling Tool", @@ -522,6 +609,7 @@ "export": 0, "if_owner": 0, "import": 0, + "is_custom": 0, "permlevel": 0, "print": 0, "read": 1, diff --git a/erpnext/schools/doctype/scheduling_tool/scheduling_tool.py b/erpnext/schools/doctype/scheduling_tool/scheduling_tool.py index 4a62a74323..b8ba578077 100644 --- a/erpnext/schools/doctype/scheduling_tool/scheduling_tool.py +++ b/erpnext/schools/doctype/scheduling_tool/scheduling_tool.py @@ -22,7 +22,9 @@ class SchedulingTool(Document): self.validate_mandatory() self.validate_date() self.instructor_name= frappe.db.get_value("Instructor", self.instructor, "instructor_name") - self.course= frappe.db.get_value("Student Group", self.student_group, "course") + + if self.student_group: + self.course= frappe.db.get_value("Student Group", self.student_group, "course") if self.rechedule: rescheduled, reschedule_errors = self.delete_course_schedule(rescheduled, reschedule_errors) @@ -54,7 +56,11 @@ class SchedulingTool(Document): def validate_mandatory(self): """Validates all mandatory fields""" - fields = ['student_group', 'room', 'instructor', 'from_time', 'to_time', 'course_start_date', 'course_end_date', 'day'] + + if not (self.student_batch or self.student_group): + frappe.throw(_("""Student Batch or Student Group is mandatory""")) + + fields = ['course', 'room', 'instructor', 'from_time', 'to_time', 'course_start_date', 'course_end_date', 'day'] for d in fields: if not self.get(d): frappe.throw(_("{0} is mandatory").format(self.meta.get_label(d))) @@ -68,6 +74,8 @@ class SchedulingTool(Document): """Delete all course schedule within the Date range and specified filters""" schedules = frappe.get_list("Course Schedule", fields=["name", "schedule_date"], filters = [["student_group", "=", self.student_group], + ["student_batch", "=", self.student_batch], + ["course", "=", self.course], ["schedule_date", ">=", self.course_start_date], ["schedule_date", "<=", self.course_end_date]]) for d in schedules: @@ -85,6 +93,7 @@ class SchedulingTool(Document): course_schedule = frappe.new_doc("Course Schedule") course_schedule.student_group = self.student_group + course_schedule.student_batch = self.student_batch course_schedule.course = self.course course_schedule.instructor = self.instructor course_schedule.instructor_name = self.instructor_name diff --git a/erpnext/schools/doctype/student_attendance/student_attendance.js b/erpnext/schools/doctype/student_attendance/student_attendance.js index 5068208288..6e79d52ec2 100644 --- a/erpnext/schools/doctype/student_attendance/student_attendance.js +++ b/erpnext/schools/doctype/student_attendance/student_attendance.js @@ -1,6 +1,9 @@ // Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt +cur_frm.add_fetch("course_schedule", "schedule_date", "date"); +cur_frm.add_fetch("course_schedule", "student_batch", "student_batch"); + frappe.ui.form.on('Student Attendance', { refresh: function(frm) { diff --git a/erpnext/schools/doctype/student_attendance/student_attendance.json b/erpnext/schools/doctype/student_attendance/student_attendance.json index 9caa9ae7fe..70fcdf353c 100644 --- a/erpnext/schools/doctype/student_attendance/student_attendance.json +++ b/erpnext/schools/doctype/student_attendance/student_attendance.json @@ -46,18 +46,18 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "student_name", - "fieldtype": "Read Only", + "fieldname": "course_schedule", + "fieldtype": "Link", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, - "in_list_view": 0, + "in_list_view": 1, "in_standard_filter": 0, - "label": "Student Name", + "label": "Course Schedule", "length": 0, "no_copy": 0, - "options": "student.title", + "options": "Course Schedule", "permlevel": 0, "precision": "", "print_hide": 0, @@ -70,6 +70,34 @@ "set_only_once": 0, "unique": 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_list_view": 0, + "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": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, { "allow_on_submit": 0, "bold": 0, @@ -102,18 +130,18 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "course_schedule", - "fieldtype": "Link", + "fieldname": "student_name", + "fieldtype": "Read Only", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, - "in_list_view": 1, + "in_list_view": 0, "in_standard_filter": 0, - "label": "Course Schedule", + "label": "Student Name", "length": 0, "no_copy": 0, - "options": "Course Schedule", + "options": "student.title", "permlevel": 0, "precision": "", "print_hide": 0, @@ -121,7 +149,36 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "unique": 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_list_view": 0, + "in_standard_filter": 0, + "label": "Student Batch", + "length": 0, + "no_copy": 0, + "options": "Student Batch", + "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 @@ -195,7 +252,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-11-07 05:29:02.601819", + "modified": "2016-11-16 16:58:35.779867", "modified_by": "Administrator", "module": "Schools", "name": "Student Attendance", diff --git a/erpnext/schools/doctype/student_attendance/student_attendance.py b/erpnext/schools/doctype/student_attendance/student_attendance.py index 65dbd68dbe..d9949b0850 100644 --- a/erpnext/schools/doctype/student_attendance/student_attendance.py +++ b/erpnext/schools/doctype/student_attendance/student_attendance.py @@ -9,13 +9,31 @@ from frappe import _ class StudentAttendance(Document): def validate(self): + self.validate_date() + self.validate_mandatory() self.validate_duplication() + def validate_date(self): + if self.course_schedule: + self.date = frappe.db.get_value("Course Schedule", self.course_schedule, "schedule_date") + + def validate_mandatory(self): + if not (self.student_batch or self.course_schedule): + frappe.throw(_("""Student Batch or Course Schedule is mandatory""")) + def validate_duplication(self): """Check if the Attendance Record is Unique""" - attendance_records= frappe.db.sql("""select name from `tabStudent Attendance` where \ - student= %s and course_schedule= %s and name != %s""", - (self.student, self.course_schedule, self.name)) + + attendance_records=None + if self.course_schedule: + attendance_records= frappe.db.sql("""select name from `tabStudent Attendance` where \ + student= %s and course_schedule= %s and name != %s and docstatus=1""", + (self.student, self.course_schedule, self.name)) + else: + attendance_records= frappe.db.sql("""select name from `tabStudent Attendance` where \ + student= %s and date= %s and name != %s and course_schedule='' and docstatus=1""", + (self.student, self.date, self.name)) + if attendance_records: - frappe.throw(_("Attendance Record {0} exists against Student {1} for Course Schedule {2}") - .format(attendance_records[0][0], self.student, self.course_schedule)) + frappe.throw(_("Attendance Record {0} exists against Student {1}") + .format(attendance_records[0][0], self.student)) diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/__init__.py b/erpnext/schools/doctype/student_batch_attendance_tool/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.js b/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.js new file mode 100644 index 0000000000..a6d035a6e6 --- /dev/null +++ b/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.js @@ -0,0 +1,128 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +frappe.provide("schools") + +frappe.ui.form.on('Student Batch Attendance Tool', { + refresh: function(frm) { + frm.disable_save(); + hide_field('attendance'); + }, + + student_batch :function(frm) { + if(frm.doc.student_batch && frm.doc.date) { + frappe.call({ + method: "erpnext.schools.api.check_attendance_records_exist", + args: { + "student_batch": frm.doc.student_batch, + "date": frm.doc.date + }, + callback: function(r) { + if(r.message) { + frappe.msgprint("Attendance already marked."); + hide_field('attendance'); + } + else { + frappe.call({ + method: "erpnext.schools.api.get_student_batch_students", + args: { + "student_batch": frm.doc.student_batch + }, + callback: function(r) { + if (r.message) { + unhide_field('attendance'); + frm.events.get_students(frm, r.message) + } + } + }); + } + } + }); + } + }, + + date: function(frm) { + frm.trigger("student_batch"); + }, + + get_students: function(frm, students) { + if(!frm.students_area) { + frm.students_area = $('
') + .appendTo(frm.fields_dict.students_html.wrapper); + } + frm.students_editor = new schools.StudentsEditor(frm, frm.students_area, students) + } +}); + + +schools.StudentsEditor = Class.extend({ + init: function(frm, wrapper, students) { + this.wrapper = wrapper; + this.frm = frm; + this.make(frm, students); + }, + make: function(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).is(":checked")) { + 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).is(":checked")) { + check.checked = false; + } + }); + }); + + student_toolbar.find(".btn-mark-att") + .html(__('Mark Attendence')) + .on("click", function() { + var students_present = []; + var students_absent = []; + $(me.wrapper).find('input[type="checkbox"]').each(function(i, check) { + if($(check).is(":checked")) { + students_present.push(students[i]); + } + else { + students_absent.push(students[i]); + } + }); + frappe.call({ + method: "erpnext.schools.api.mark_attendance", + args: { + "students_present": students_present, + "students_absent": students_absent, + "student_batch": frm.doc.student_batch, + "date": frm.doc.date + }, + callback: function(r) { + hide_field('attendance'); + } + }); + }); + + + $.each(students, function(i, m) { + $(repl('
\ +
\ + \ +
', {student: m.student_name})).appendTo(me.wrapper); + }); + } +}); diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.json b/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.json new file mode 100644 index 0000000000..3361dcb44c --- /dev/null +++ b/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.json @@ -0,0 +1,201 @@ +{ + "allow_copy": 1, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2016-11-16 17:12:46.437539", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "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_list_view": 0, + "in_standard_filter": 0, + "label": "Student Batch", + "length": 0, + "no_copy": 0, + "options": "Student Batch", + "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_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_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_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_list_view": 0, + "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": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "", + "fieldname": "attendance", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Attendance", + "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_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "students_html", + "fieldtype": "HTML", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Students HTML", + "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 + } + ], + "hide_heading": 1, + "hide_toolbar": 1, + "idx": 0, + "image_view": 0, + "in_create": 0, + "in_dialog": 0, + "is_submittable": 0, + "issingle": 1, + "istable": 0, + "max_attachments": 0, + "modified": "2016-11-16 17:16:43.835693", + "modified_by": "Administrator", + "module": "Schools", + "name": "Student Batch Attendance Tool", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 0, + "cancel": 0, + "create": 1, + "delete": 0, + "email": 1, + "export": 0, + "if_owner": 0, + "import": 0, + "is_custom": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 0, + "role": "Academics User", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 0, + "read_only": 0, + "read_only_onload": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.py b/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.py new file mode 100644 index 0000000000..49a5ae8a34 --- /dev/null +++ b/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document + +class StudentBatchAttendanceTool(Document): + pass