diff --git a/erpnext/schools/doctype/student_leave_application/student_leave_application.json b/erpnext/schools/doctype/student_leave_application/student_leave_application.json index f183afc442f..ad6d498cb07 100644 --- a/erpnext/schools/doctype/student_leave_application/student_leave_application.json +++ b/erpnext/schools/doctype/student_leave_application/student_leave_application.json @@ -103,7 +103,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "date", + "fieldname": "from_date", "fieldtype": "Date", "hidden": 0, "ignore_user_permissions": 0, @@ -111,7 +111,7 @@ "in_filter": 0, "in_list_view": 1, "in_standard_filter": 1, - "label": "Date", + "label": "From Date", "length": 0, "no_copy": 0, "permlevel": 0, @@ -126,6 +126,63 @@ "set_only_once": 0, "unique": 0 }, + { + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "to_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "To 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, + "description": "Will show the student as Present in Student Monthly Attendance Report", + "fieldname": "mark_as_present", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Mark as Present", + "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, @@ -220,7 +277,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-12-15 14:51:28.774955", + "modified": "2016-12-21 18:58:00.256114", "modified_by": "Administrator", "module": "Schools", "name": "Student Leave Application", diff --git a/erpnext/schools/report/absent_student_report/absent_student_report.py b/erpnext/schools/report/absent_student_report/absent_student_report.py index 82a20aa1265..32026c9e1b8 100644 --- a/erpnext/schools/report/absent_student_report/absent_student_report.py +++ b/erpnext/schools/report/absent_student_report/absent_student_report.py @@ -55,6 +55,6 @@ def get_absent_students(date): def get_leave_applications(date): leave_applicants = [] for student in frappe.db.sql("""select student from `tabStudent Leave Application` - where docstatus = 1 and date = %s""", date): + where docstatus = 1 and from_date <= %s and to_date >= %s""", (date, date)): leave_applicants.append(student[0]) return leave_applicants \ No newline at end of file diff --git a/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.js b/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.js index 32c05516535..8d914cba2e0 100644 --- a/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.js +++ b/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.js @@ -3,40 +3,40 @@ frappe.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"][frappe.datetime.str_to_obj(frappe.datetime.get_today()).getMonth()], - }, - { - "fieldname":"year", - "label": __("Year"), - "fieldtype": "Select", - "reqd": 1 - }, - { - "fieldname":"student_batch", - "label": __("Student Batch"), - "fieldtype": "Link", - "options": "Student Batch", - "reqd": 1 - } - ], + "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" + ][frappe.datetime.str_to_obj(frappe.datetime.get_today()).getMonth()], + }, + { + "fieldname": "year", + "label": __("Year"), + "fieldtype": "Select", + "reqd": 1 + }, + { + "fieldname": "student_batch", + "label": __("Student Batch"), + "fieldtype": "Link", + "options": "Student Batch", + "reqd": 1 + } + ], - "onload": function() { - return frappe.call({ - method: "erpnext.schools.report.student_monthly_attendance_sheet.student_monthly_attendance_sheet.get_attendance_years", - callback: function(r) { - var year_filter = frappe.query_report_filters_by_name.year; - year_filter.df.options = r.message; - year_filter.df.default = r.message.split("\n")[0]; - year_filter.refresh(); - year_filter.set_input(year_filter.df.default); - } - }); - } -} + "onload": function() { + return frappe.call({ + method: "erpnext.schools.report.student_monthly_attendance_sheet.student_monthly_attendance_sheet.get_attendance_years", + callback: function(r) { + var year_filter = frappe.query_report_filters_by_name.year; + year_filter.df.options = r.message; + year_filter.df.default = r.message.split("\n")[0]; + year_filter.refresh(); + year_filter.set_input(year_filter.df.default); + } + }); + } +} \ No newline at end of file diff --git a/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py b/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py index 2f8ba52378f..01cee583501 100644 --- a/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py +++ b/erpnext/schools/report/student_monthly_attendance_sheet/student_monthly_attendance_sheet.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import frappe -from frappe.utils import cstr, cint, getdate +from frappe.utils import cstr, cint, getdate, get_first_day, get_last_day, date_diff, add_days from frappe import msgprint, _ from calendar import monthrange from erpnext.schools.api import get_student_batch_students @@ -11,72 +11,93 @@ from erpnext.schools.api import get_student_batch_students def execute(filters=None): if not filters: filters = {} - conditions, filters = get_conditions(filters) - columns = get_columns(filters) - att_map = get_attendance_list(conditions, filters) + from_date = get_first_day(filters["month"] + '-' + filters["year"]) + to_date = get_last_day(filters["month"] + '-' + filters["year"]) + total_days_in_month = date_diff(to_date, from_date) +1 + columns = get_columns(total_days_in_month) students = get_student_batch_students(filters.get("student_batch")) + students_list = get_students_list(students) + att_map = get_attendance_list(from_date, to_date, filters.get("student_batch"), students_list) data = [] for stud in students: row = [stud.student, stud.student_name] - + date = from_date total_p = total_a = 0.0 - for day in range(filters["total_days_in_month"]): + for day in range(total_days_in_month): status="None" if att_map.get(stud.student): - status = att_map.get(stud.student).get(day + 1, "None") + status = att_map.get(stud.student).get(date, "None") status_map = {"Present": "P", "Absent": "A", "None": ""} 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(filters): +def get_columns(days_in_month): columns = [ _("Student") + ":Link/Student:90", _("Student Name") + "::150"] - - for day in range(filters["total_days_in_month"]): + 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_attendance_list(conditions, filters): - attendance_list = frappe.db.sql("""select student, day(date) as day_of_month, - status from `tabStudent Attendance` where docstatus = 1 %s order by student, date""" % - conditions, filters, as_dict=1) +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_batch, students_list): + attendance_list = frappe.db.sql("""select student, date, status + from `tabStudent Attendance` where docstatus = 1 and student_batch = %s + and date between %s and %s + order by student, date""", + (student_batch, 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, frappe._dict()).setdefault(d.day_of_month, "") - att_map[d.student][d.day_of_month] = d.status - + att_map.setdefault(d.student, frappe._dict()).setdefault(d.date, "") + if students_with_leave_application 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 return att_map -def get_conditions(filters): - if not (filters.get("month") and filters.get("year")): - msgprint(_("Please select month and year"), raise_exception=1) +def get_students_with_leave_application(from_date, to_date, students_list): + leave_applications = frappe.db.sql(""" + select student, from_date, to_date + from `tabStudent Leave Application` + where + mark_as_present 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) - filters["month"] = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", - "Dec"].index(filters.month) + 1 + return students_with_leaves - filters["total_days_in_month"] = monthrange(cint(filters.year), filters.month)[1] - - conditions = " and month(date) = %(month)s and year(date) = %(year)s" - - if filters.get("student_batch"): conditions += " and student_batch = %(student_batch)s" - - return conditions, filters +def daterange(d1, d2): + import datetime + return (d1 + datetime.timedelta(days=i) for i in range((d2 - d1).days + 1)) @frappe.whitelist() def get_attendance_years(): year_list = frappe.db.sql_list("""select distinct YEAR(date) from `tabStudent Attendance` ORDER BY YEAR(date) DESC""") if not year_list: year_list = [getdate().year] - return "\n".join(str(year) for year in year_list)