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"
This commit is contained in:
Neil Trini Lasrado 2016-12-09 17:38:59 +05:30
parent e4b9473f83
commit eccbf43235
12 changed files with 242 additions and 288 deletions

View File

@ -68,7 +68,7 @@ def get_data():
},
{
"type": "doctype",
"name": "Student Batch Attendance Tool"
"name": "Student Attendance Tool"
},
{
"type": "report",

View File

@ -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"
]
}

View File

@ -0,0 +1,20 @@
<div class="col-sm-3">
<div class="checkbox {% if status %} text-muted {% endif %}">
<label>
<input
type="checkbox"
data-idx="{{idx}}"
data-student="{{student}}"
data-student-name="{{student_name}}"
class="students-check"
{% if status %}
disabled="true"
{% endif %}
{% if status === "Present" %}
checked
{% endif %}
>
{{ idx }} - {{ student_name }}
</label>
</div>
</div>

View File

@ -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)

View File

@ -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 = $('<div>')
.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 = $('<p>\
<button class="btn btn-default btn-add btn-xs" style="margin-right: 5px;"></button>\
<button class="btn btn-xs btn-default btn-remove" style="margin-right: 5px;"></button>\
<button class="btn btn-default btn-primary btn-mark-att btn-xs"></button></p>').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('<div class="col-sm-6">\
<div class="checkbox">\
<label><input type="checkbox" class="students-check" student="%(student)s">\
%(student)s</label>\
</div></div>', { student: m.student_name })).appendTo(me.wrapper);
});
}
})
});

View File

@ -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",

View File

@ -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}")

View File

@ -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 = $('<div>')
@ -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('<div class="col-sm-6">\
<div class="checkbox">\
<label><input data-idx="%(idx)s" type="checkbox" class="students-check" data-student="%(name)s">\
%(idx)s - %(name)s</label>\
</div></div>', {
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);
}
});

View File

@ -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": [

View File

@ -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

View File

@ -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