From eccbf432354b3dd2bfb54e43264529133e033b90 Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Fri, 9 Dec 2016 17:38:59 +0530 Subject: [PATCH] Renamed Student Batch Attendance Tool to Student Attendance Tool Merged code for Student Attendance against Course Schedule and Student Batch Student Attendance Tool now shows marked student attendance as well. Fixed validation login in Student Attendance for duplicate Student Attendance Record validation" --- erpnext/config/schools.py | 2 +- erpnext/public/build.json | 73 +++++----- erpnext/public/js/schools/student_button.html | 20 +++ erpnext/schools/api.py | 2 + .../course_schedule/course_schedule.js | 133 +----------------- .../course_schedule/course_schedule.json | 58 +------- .../student_attendance/student_attendance.py | 4 +- .../__init__.py | 0 .../student_attendance_tool.js} | 110 ++++++++------- .../student_attendance_tool.json} | 78 ++++++++-- .../student_attendance_tool.py | 40 ++++++ .../student_batch_attendance_tool.py | 10 -- 12 files changed, 242 insertions(+), 288 deletions(-) create mode 100644 erpnext/public/js/schools/student_button.html rename erpnext/schools/doctype/{student_batch_attendance_tool => student_attendance_tool}/__init__.py (100%) rename erpnext/schools/doctype/{student_batch_attendance_tool/student_batch_attendance_tool.js => student_attendance_tool/student_attendance_tool.js} (52%) rename erpnext/schools/doctype/{student_batch_attendance_tool/student_batch_attendance_tool.json => student_attendance_tool/student_attendance_tool.json} (72%) create mode 100644 erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.py delete 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 f9696d0b46..1d33d4d096 100644 --- a/erpnext/config/schools.py +++ b/erpnext/config/schools.py @@ -68,7 +68,7 @@ def get_data(): }, { "type": "doctype", - "name": "Student Batch Attendance Tool" + "name": "Student Attendance Tool" }, { "type": "report", diff --git a/erpnext/public/build.json b/erpnext/public/build.json index ac1c7c3205..30b09000fd 100644 --- a/erpnext/public/build.json +++ b/erpnext/public/build.json @@ -1,37 +1,38 @@ { - "css/erpnext.css": [ - "public/css/erpnext.css" - ], - "js/erpnext-web.min.js": [ - "public/js/website_utils.js", - "public/js/shopping_cart.js" - ], - "js/erpnext.min.js": [ - "public/js/conf.js", - "public/js/utils.js", - "public/js/queries.js", - "public/js/sms_manager.js", - "public/js/utils/party.js", - "public/js/templates/address_list.html", - "public/js/templates/contact_list.html", - "public/js/controllers/stock_controller.js", - "public/js/payment/payments.js", - "public/js/controllers/taxes_and_totals.js", - "public/js/controllers/transaction.js", - "public/js/pos/pos.html", - "public/js/pos/pos_bill_item.html", - "public/js/pos/pos_item.html", - "public/js/pos/pos_tax_row.html", - "public/js/pos/pos_invoice_list.html", - "public/js/payment/pos_payment.html", - "public/js/payment/payment_details.html", - "public/js/templates/item_selector.html", - "public/js/utils/item_selector.js", - "public/js/help_links.js" - ], - "js/item-dashboard.min.js": [ - "stock/dashboard/item_dashboard.html", - "stock/dashboard/item_dashboard_list.html", - "stock/dashboard/item_dashboard.js" - ] -} + "css/erpnext.css": [ + "public/css/erpnext.css" + ], + "js/erpnext-web.min.js": [ + "public/js/website_utils.js", + "public/js/shopping_cart.js" + ], + "js/erpnext.min.js": [ + "public/js/conf.js", + "public/js/utils.js", + "public/js/queries.js", + "public/js/sms_manager.js", + "public/js/utils/party.js", + "public/js/templates/address_list.html", + "public/js/templates/contact_list.html", + "public/js/controllers/stock_controller.js", + "public/js/payment/payments.js", + "public/js/controllers/taxes_and_totals.js", + "public/js/controllers/transaction.js", + "public/js/pos/pos.html", + "public/js/pos/pos_bill_item.html", + "public/js/pos/pos_item.html", + "public/js/pos/pos_tax_row.html", + "public/js/pos/pos_invoice_list.html", + "public/js/payment/pos_payment.html", + "public/js/payment/payment_details.html", + "public/js/templates/item_selector.html", + "public/js/utils/item_selector.js", + "public/js/help_links.js", + "public/js/schools/student_button.html" + ], + "js/item-dashboard.min.js": [ + "stock/dashboard/item_dashboard.html", + "stock/dashboard/item_dashboard_list.html", + "stock/dashboard/item_dashboard.js" + ] +} \ No newline at end of file diff --git a/erpnext/public/js/schools/student_button.html b/erpnext/public/js/schools/student_button.html new file mode 100644 index 0000000000..dabaf2660e --- /dev/null +++ b/erpnext/public/js/schools/student_button.html @@ -0,0 +1,20 @@ +
+
+ +
+
\ No newline at end of file diff --git a/erpnext/schools/api.py b/erpnext/schools/api.py index 7cb02a3793..bf09351ff5 100644 --- a/erpnext/schools/api.py +++ b/erpnext/schools/api.py @@ -52,8 +52,10 @@ def mark_attendance(students_present, students_absent, course_schedule=None, stu :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"], "Present", course_schedule, student_batch, date) diff --git a/erpnext/schools/doctype/course_schedule/course_schedule.js b/erpnext/schools/doctype/course_schedule/course_schedule.js index 04a8cdedf2..12e852215a 100644 --- a/erpnext/schools/doctype/course_schedule/course_schedule.js +++ b/erpnext/schools/doctype/course_schedule/course_schedule.js @@ -1,134 +1,15 @@ frappe.provide("schools") frappe.ui.form.on("Course Schedule", { - onload: function(frm) { - if (frm.doc.from_datetime && frm.doc.to_datetime) { - var from_datetime = moment(frm.doc.from_datetime); - var to_datetime = moment(frm.doc.to_datetime); - frm.doc.schedule_date = from_datetime.format(moment.defaultFormat); - frm.doc.from_time = from_datetime.format("HH:mm:ss"); - frm.doc.to_time = to_datetime.format("HH:mm:ss"); - } - }, - refresh: function(frm) { - if (!frm.doc.__islocal && frm.doc.student_group) { - frappe.call({ - method: "erpnext.schools.api.check_attendance_records_exist", - args: { - "course_schedule": frm.doc.name - }, - callback: function(r) { - if (r.message) { - hide_field('attendance'); - frm.events.view_attendance(frm) - } else { - frappe.call({ - method: "erpnext.schools.api.get_student_group_students", - args: { - "student_group": frm.doc.student_group - }, - callback: function(r) { - if (r.message) { - frm.events.get_students(frm, r.message) - } - } - }); - } + if (!frm.doc.__islocal) { + frm.add_custom_button(__("Attendance"), function() { + frappe.route_options = { + based_on: "Course Schedule", + course_schedule: frm.doc.name } + frappe.set_route("Form", "Student Attendance Tool"); }); - } else { - hide_field('attendance'); } - }, - - view_attendance: function(frm) { - hide_field('attendance'); - frm.add_custom_button(__("View attendance"), function() { - frappe.route_options = { - course_schedule: frm.doc.name - } - frappe.set_route("List", "Student Attendance"); - }); - }, - - 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, - "course_schedule": frm.doc.name - }, - callback: function(r) { - frm.events.view_attendance(frm) - } - }); - }); - - - $.each(students, function(i, m) { - $(repl('
\ -
\ - \ -
', { student: m.student_name })).appendTo(me.wrapper); - }); - } -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/erpnext/schools/doctype/course_schedule/course_schedule.json b/erpnext/schools/doctype/course_schedule/course_schedule.json index 122285e980..450d7cfad2 100644 --- a/erpnext/schools/doctype/course_schedule/course_schedule.json +++ b/erpnext/schools/doctype/course_schedule/course_schedule.json @@ -382,62 +382,6 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "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": 1, - "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, @@ -478,7 +422,7 @@ "istable": 0, "max_attachments": 0, "menu_index": 0, - "modified": "2016-12-01 12:59:25.086606", + "modified": "2016-12-09 17:00:02.822788", "modified_by": "Administrator", "module": "Schools", "name": "Course Schedule", diff --git a/erpnext/schools/doctype/student_attendance/student_attendance.py b/erpnext/schools/doctype/student_attendance/student_attendance.py index 45b3014579..e2d01b56bd 100644 --- a/erpnext/schools/doctype/student_attendance/student_attendance.py +++ b/erpnext/schools/doctype/student_attendance/student_attendance.py @@ -31,9 +31,9 @@ class StudentAttendance(Document): (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 docstatus=1 and \ + student= %s and student_batch= %s and date= %s and name != %s and docstatus=1 and \ (course_schedule is Null or course_schedule='')""", - (self.student, self.date, self.name)) + (self.student, self.student_batch, self.date, self.name)) if attendance_records: frappe.throw(_("Attendance Record {0} exists against Student {1}") diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/__init__.py b/erpnext/schools/doctype/student_attendance_tool/__init__.py similarity index 100% rename from erpnext/schools/doctype/student_batch_attendance_tool/__init__.py rename to erpnext/schools/doctype/student_attendance_tool/__init__.py diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.js b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.js similarity index 52% rename from erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.js rename to erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.js index 2dc6a85d4a..7dd9dda259 100644 --- a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.js +++ b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.js @@ -2,40 +2,35 @@ // For license information, please see license.txt frappe.provide("schools") -frappe.ui.form.on('Student Batch Attendance Tool', { +frappe.ui.form.on('Student Attendance Tool', { refresh: function(frm) { frm.disable_save(); - hide_field('attendance'); + }, + + based_on: function(frm) { + if (frm.doc.based_on == "Student Batch") { + frm.set_value("course_schedule", ""); + } else { + frm.set_value("student_batch", ""); + } }, student_batch: function(frm) { - if (frm.doc.student_batch && frm.doc.date) { + if ((frm.doc.student_batch && frm.doc.date) || frm.doc.course_schedule) { + var method = "erpnext.schools.doctype.student_attendance_tool.student_attendance_tool.get_student_attendance_records"; + frappe.call({ - method: "erpnext.schools.api.check_attendance_records_exist", + method: method, args: { - "student_batch": frm.doc.student_batch, - "date": frm.doc.date + based_on: frm.doc.based_on, + student_batch: frm.doc.student_batch, + date: frm.doc.date, + course_schedule: frm.doc.course_schedule }, 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) - } - } - }); - } + frm.events.get_students(frm, r.message); } - }); + }) } }, @@ -43,6 +38,10 @@ frappe.ui.form.on('Student Batch Attendance Tool', { frm.trigger("student_batch"); }, + course_schedule: function(frm) { + frm.trigger("student_batch"); + }, + get_students: function(frm, students) { if (!frm.students_area) { frm.students_area = $('
') @@ -72,7 +71,7 @@ schools.StudentsEditor = Class.extend({ .html(__('Check all')) .on("click", function() { $(me.wrapper).find('input[type="checkbox"]').each(function(i, check) { - if (!$(check).is(":checked")) { + if (!$(check).prop("disabled")) { check.checked = true; } }); @@ -82,55 +81,70 @@ schools.StudentsEditor = Class.extend({ .html(__('Uncheck all')) .on("click", function() { $(me.wrapper).find('input[type="checkbox"]').each(function(i, check) { - if ($(check).is(":checked")) { + if (!$(check).prop("disabled")) { check.checked = false; } }); }); - var get_student = function(idx) { + var get_present_student = function(student) { return students.filter(function(s) { return s.idx === idx; - })[0] + }) + } + var get_absent_student = function(idx) { + return students.filter(function(s) { + return s.idx === idx; + }) } 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) { - var idx = $(check).data().idx; - if ($(check).is(":checked")) { - students_present.push(get_student(idx)); - } else { - students_absent.push(get_student(idx)); - } + 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, + idx: $check.data().idx, + 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; + }); + frappe.call({ method: "erpnext.schools.api.mark_attendance", args: { "students_present": students_present, "students_absent": students_absent, "student_batch": frm.doc.student_batch, + "course_schedule": frm.doc.course_schedule, "date": frm.doc.date }, callback: function(r) { - hide_field('attendance'); + frm.trigger("student_batch"); } }); }); - - $.each(students, function(i, m) { - $(repl('
\ -
\ - \ -
', { - name: m.student_name, - idx: m.idx - })).appendTo(me.wrapper); + var htmls = students.map(function(student) { + return frappe.render_template("student_button", { + student: student.student, + student_name: student.student_name, + idx: student.idx, + status: student.status + }) }); + + $(htmls.join("")).appendTo(me.wrapper); } }); \ No newline at end of file diff --git a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.json b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.json similarity index 72% rename from erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.json rename to erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.json index defc886b1c..092af041a9 100644 --- a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.json +++ b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.json @@ -16,18 +16,19 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "student_batch", - "fieldtype": "Link", + "default": "", + "fieldname": "based_on", + "fieldtype": "Select", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Student Batch", + "label": "Based On", "length": 0, "no_copy": 0, - "options": "Student Batch", + "options": "Student Batch\nCourse Schedule", "permlevel": 0, "precision": "", "print_hide": 0, @@ -35,7 +36,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 @@ -72,6 +73,67 @@ "bold": 0, "collapsible": 0, "columns": 0, + "depends_on": "eval:doc.based_on ==\"Student Batch\"", + "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, + "depends_on": "eval:doc.based_on ==\"Course Schedule\"", + "fieldname": "course_schedule", + "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 Schedule", + "length": 0, + "no_copy": 0, + "options": "Course Schedule", + "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": "eval:doc.based_on ==\"Student Batch\"", "fieldname": "date", "fieldtype": "Date", "hidden": 0, @@ -100,7 +162,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "depends_on": "", + "depends_on": "eval: (doc.course_schedule \n|| (doc.student_batch && doc.date))", "fieldname": "attendance", "fieldtype": "Section Break", "hidden": 0, @@ -163,10 +225,10 @@ "issingle": 1, "istable": 0, "max_attachments": 0, - "modified": "2016-12-01 12:58:31.822014", + "modified": "2016-12-09 17:36:28.739318", "modified_by": "Administrator", "module": "Schools", - "name": "Student Batch Attendance Tool", + "name": "Student Attendance Tool", "name_case": "", "owner": "Administrator", "permissions": [ diff --git a/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.py b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.py new file mode 100644 index 0000000000..30a692cf18 --- /dev/null +++ b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.py @@ -0,0 +1,40 @@ +# -*- 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 StudentAttendanceTool(Document): + pass + +@frappe.whitelist() +def get_student_attendance_records(based_on, date=None, student_batch=None, course_schedule=None): + student_list = [] + student_attendance_list = [] + + if based_on=="Course Schedule": + student_group = frappe.db.get_value("Course Schedule", course_schedule, "student_group") + if student_group: + student_list = frappe.get_list("Student Group Student", fields=["student", "student_name", "idx"] , \ + filters={"parent": student_group}, order_by= "idx") + else: + student_batch = frappe.db.get_value("Course Schedule", course_schedule, "student_batch") + if not student_list: + student_list = frappe.get_list("Student Batch Student", fields=["student", "student_name", "idx"] , filters={"parent": student_batch}, order_by= "idx") + + if course_schedule: + student_attendance_list= frappe.db.sql("""select student, status from `tabStudent Attendance` where \ + course_schedule= %s and docstatus=1""", (course_schedule), as_dict=1) + else: + student_attendance_list= frappe.db.sql("""select student, status from `tabStudent Attendance` where \ + student_batch= %s and date= %s and docstatus=1 and \ + (course_schedule is Null or course_schedule='')""", + (student_batch, date), as_dict=1) + + for attendance in student_attendance_list: + for student in student_list: + if student.student == attendance.student: + student.status = attendance.status + return student_list \ 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 deleted file mode 100644 index 49a5ae8a34..0000000000 --- a/erpnext/schools/doctype/student_batch_attendance_tool/student_batch_attendance_tool.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- 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