From 5142fc9365617af3be73c2aeb4002691096e7e42 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Thu, 23 Jul 2020 15:57:27 +0530 Subject: [PATCH] feat(Education): added form dashboards and refactored custom buttons for better linking (#22727) * feat: add form dashboards to all forms in Education Module * feat: Add Course to Programs button in Course DocType * refactor: custom buttons in Education module forms * feat: buttons to add topic, article, quiz to their respective parent doctypes * feat: add charts to form dashboards * fix: code cleanup --- .../academic_term/academic_term_dashboard.py | 25 + .../doctype/academic_year/academic_year.js | 10 +- .../academic_year/academic_year_dashboard.py | 25 + erpnext/education/doctype/article/article.js | 48 + erpnext/education/doctype/article/article.py | 12 +- .../assessment_group_dashboard.py | 15 + .../assessment_plan/assessment_plan.js | 18 +- .../assessment_plan_dashboard.py | 8 +- .../assessment_result/assessment_result.js | 61 +- .../assessment_result_dashboard.py | 14 + erpnext/education/doctype/course/course.js | 89 +- erpnext/education/doctype/course/course.py | 34 +- .../doctype/course/course_dashboard.py | 8 +- .../course_enrollment_dashboard.py | 15 + .../course_schedule/course_schedule.js | 4 +- .../course_schedule/course_schedule.json | 966 +++++++++--------- .../course_schedule_dashboard.py | 15 + .../doctype/fee_schedule/fee_schedule.js | 75 +- .../fee_schedule/fee_schedule_dashboard.py | 13 + .../doctype/fee_structure/fee_structure.js | 28 +- .../fee_structure/fee_structure_dashboard.py | 15 + .../grading_scale/grading_scale_dashboard.py | 20 + .../doctype/instructor/instructor.js | 28 +- .../doctype/instructor/instructor.py | 12 +- .../instructor/instructor_dashboard.py | 24 + .../doctype/program/program_dashboard.py | 8 +- .../program_enrollment_dashboard.py | 19 + erpnext/education/doctype/quiz/quiz.js | 56 +- erpnext/education/doctype/quiz/quiz.py | 10 + erpnext/education/doctype/room/room.js | 10 +- .../education/doctype/room/room_dashboard.py | 19 + .../student_attendance_dashboard.py | 12 + .../student_category_dashboard.py | 13 + .../doctype/student_group/student_group.js | 109 +- .../student_group/student_group_dashboard.py | 19 + erpnext/education/doctype/topic/topic.js | 47 + erpnext/education/doctype/topic/topic.py | 44 +- 37 files changed, 1249 insertions(+), 699 deletions(-) create mode 100644 erpnext/education/doctype/academic_term/academic_term_dashboard.py create mode 100644 erpnext/education/doctype/academic_year/academic_year_dashboard.py create mode 100644 erpnext/education/doctype/assessment_group/assessment_group_dashboard.py create mode 100644 erpnext/education/doctype/assessment_result/assessment_result_dashboard.py create mode 100644 erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py create mode 100644 erpnext/education/doctype/course_schedule/course_schedule_dashboard.py create mode 100644 erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py create mode 100644 erpnext/education/doctype/fee_structure/fee_structure_dashboard.py create mode 100644 erpnext/education/doctype/grading_scale/grading_scale_dashboard.py create mode 100644 erpnext/education/doctype/instructor/instructor_dashboard.py create mode 100644 erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py create mode 100644 erpnext/education/doctype/room/room_dashboard.py create mode 100644 erpnext/education/doctype/student_attendance/student_attendance_dashboard.py create mode 100644 erpnext/education/doctype/student_category/student_category_dashboard.py create mode 100644 erpnext/education/doctype/student_group/student_group_dashboard.py diff --git a/erpnext/education/doctype/academic_term/academic_term_dashboard.py b/erpnext/education/doctype/academic_term/academic_term_dashboard.py new file mode 100644 index 0000000000..871e0f3284 --- /dev/null +++ b/erpnext/education/doctype/academic_term/academic_term_dashboard.py @@ -0,0 +1,25 @@ +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'fieldname': 'academic_term', + 'transactions': [ + { + 'label': _('Student'), + 'items': ['Student Applicant', 'Student Group', 'Student Log'] + }, + { + 'label': _('Fee'), + 'items': ['Fees', 'Fee Schedule', 'Fee Structure'] + }, + { + 'label': _('Program'), + 'items': ['Program Enrollment'] + }, + { + 'label': _('Assessment'), + 'items': ['Assessment Plan', 'Assessment Result'] + } + ] + } \ No newline at end of file diff --git a/erpnext/education/doctype/academic_year/academic_year.js b/erpnext/education/doctype/academic_year/academic_year.js index 21caa63369..0e8619849c 100644 --- a/erpnext/education/doctype/academic_year/academic_year.js +++ b/erpnext/education/doctype/academic_year/academic_year.js @@ -1,10 +1,2 @@ -frappe.ui.form.on("Academic Year", "refresh", function(frm) { - if(!frm.doc.__islocal) { - frm.add_custom_button(__("Student Group"), function() { - frappe.route_options = { - academic_year: frm.doc.name - } - frappe.set_route("List", "Student Group"); - }); - } +frappe.ui.form.on("Academic Year", { }); \ No newline at end of file diff --git a/erpnext/education/doctype/academic_year/academic_year_dashboard.py b/erpnext/education/doctype/academic_year/academic_year_dashboard.py new file mode 100644 index 0000000000..f27f7d14cf --- /dev/null +++ b/erpnext/education/doctype/academic_year/academic_year_dashboard.py @@ -0,0 +1,25 @@ +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'fieldname': 'academic_year', + 'transactions': [ + { + 'label': _('Student'), + 'items': ['Student Admission', 'Student Applicant', 'Student Group', 'Student Log'] + }, + { + 'label': _('Fee'), + 'items': ['Fees', 'Fee Schedule', 'Fee Structure'] + }, + { + 'label': _('Academic Term and Program'), + 'items': ['Academic Term', 'Program Enrollment'] + }, + { + 'label': _('Assessment'), + 'items': ['Assessment Plan', 'Assessment Result'] + } + ] + } \ No newline at end of file diff --git a/erpnext/education/doctype/article/article.js b/erpnext/education/doctype/article/article.js index 4c9c6f01f0..edfec26273 100644 --- a/erpnext/education/doctype/article/article.js +++ b/erpnext/education/doctype/article/article.js @@ -3,6 +3,54 @@ frappe.ui.form.on('Article', { refresh: function(frm) { + if (!frm.doc.__islocal) { + frm.add_custom_button(__('Add to Topics'), function() { + frm.trigger('add_article_to_topics'); + }, __('Action')); + } + }, + add_article_to_topics: function(frm) { + get_topics_without_article(frm.doc.name).then(r => { + if (r.message.length) { + frappe.prompt([ + { + fieldname: 'topics', + label: __('Topics'), + fieldtype: 'MultiSelectPills', + get_data: function() { + return r.message; + } + } + ], + function(data) { + frappe.call({ + method: 'erpnext.education.doctype.topic.topic.add_content_to_topics', + args: { + 'content_type': 'Article', + 'content': frm.doc.name, + 'topics': data.topics, + }, + callback: function(r) { + if (!r.exc) { + frm.reload_doc(); + } + }, + freeze: true, + freeze_message: __('...Adding Article to Topics') + }); + }, __('Add Article to Topics'), __('Add')); + } else { + frappe.msgprint(__('This article is already added to the existing topics')); + } + }); } }); + +let get_topics_without_article = function(article) { + return frappe.call({ + type: 'GET', + method: 'erpnext.education.doctype.article.article.get_topics_without_article', + args: {'article': article} + }); +}; \ No newline at end of file diff --git a/erpnext/education/doctype/article/article.py b/erpnext/education/doctype/article/article.py index 7dc850be37..8ba367da76 100644 --- a/erpnext/education/doctype/article/article.py +++ b/erpnext/education/doctype/article/article.py @@ -7,9 +7,15 @@ import frappe from frappe.model.document import Document class Article(Document): - - def get_article(self): pass - +@frappe.whitelist() +def get_topics_without_article(article): + data = [] + for entry in frappe.db.get_all('Topic'): + topic = frappe.get_doc('Topic', entry.name) + topic_contents = [tc.content for tc in topic.topic_content] + if not topic_contents or article not in topic_contents: + data.append(topic.name) + return data \ No newline at end of file diff --git a/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py b/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py new file mode 100644 index 0000000000..2649d4b90c --- /dev/null +++ b/erpnext/education/doctype/assessment_group/assessment_group_dashboard.py @@ -0,0 +1,15 @@ +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'fieldname': 'assessment_group', + 'transactions': [ + { + 'label': _('Assessment'), + 'items': ['Assessment Plan', 'Assessment Result'] + } + ] + } \ No newline at end of file diff --git a/erpnext/education/doctype/assessment_plan/assessment_plan.js b/erpnext/education/doctype/assessment_plan/assessment_plan.js index 0cb642bb6b..c4c56143c3 100644 --- a/erpnext/education/doctype/assessment_plan/assessment_plan.js +++ b/erpnext/education/doctype/assessment_plan/assessment_plan.js @@ -2,9 +2,9 @@ // For license information, please see license.txt -frappe.ui.form.on("Assessment Plan", { +frappe.ui.form.on('Assessment Plan', { onload: function(frm) { - frm.set_query("assessment_group", function(doc, cdt, cdn) { + frm.set_query('assessment_group', function(doc, cdt, cdn) { return{ filters: { 'is_group': 0 @@ -22,20 +22,20 @@ frappe.ui.form.on("Assessment Plan", { refresh: function(frm) { if (frm.doc.docstatus == 1) { - frm.add_custom_button(__("Assessment Result"), function() { + frm.add_custom_button(__('Assessment Result Tool'), function() { frappe.route_options = { assessment_plan: frm.doc.name, student_group: frm.doc.student_group } - frappe.set_route("Form", "Assessment Result Tool"); - }); + frappe.set_route('Form', 'Assessment Result Tool'); + }, __('Tools')); } }, course: function(frm) { if (frm.doc.course && frm.doc.maximum_assessment_score) { frappe.call({ - method: "erpnext.education.api.get_assessment_criteria", + method: 'erpnext.education.api.get_assessment_criteria', args: { course: frm.doc.course }, @@ -43,12 +43,12 @@ frappe.ui.form.on("Assessment Plan", { if (r.message) { frm.doc.assessment_criteria = []; $.each(r.message, function(i, d) { - var row = frappe.model.add_child(frm.doc, "Assessment Plan Criteria", "assessment_criteria"); + var row = frappe.model.add_child(frm.doc, 'Assessment Plan Criteria', 'assessment_criteria'); row.assessment_criteria = d.assessment_criteria; row.maximum_score = d.weightage / 100 * frm.doc.maximum_assessment_score; }); } - refresh_field("assessment_criteria"); + refresh_field('assessment_criteria'); } }); @@ -56,6 +56,6 @@ frappe.ui.form.on("Assessment Plan", { }, maximum_assessment_score: function(frm) { - frm.trigger("course"); + frm.trigger('course'); } }); \ No newline at end of file diff --git a/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py b/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py index c36dfb11b5..5e6c29dcdf 100644 --- a/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py +++ b/erpnext/education/doctype/assessment_plan/assessment_plan_dashboard.py @@ -6,12 +6,16 @@ from frappe import _ def get_data(): return { 'fieldname': 'assessment_plan', - 'non_standard_fieldnames': { - }, 'transactions': [ { 'label': _('Assessment'), 'items': ['Assessment Result'] } + ], + 'reports': [ + { + 'label': _('Report'), + 'items': ['Assessment Plan Status'] + } ] } \ No newline at end of file diff --git a/erpnext/education/doctype/assessment_result/assessment_result.js b/erpnext/education/doctype/assessment_result/assessment_result.js index 84865ca8ec..12fdd91c25 100644 --- a/erpnext/education/doctype/assessment_result/assessment_result.js +++ b/erpnext/education/doctype/assessment_result/assessment_result.js @@ -1,7 +1,13 @@ // Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt -frappe.ui.form.on("Assessment Result", { +frappe.ui.form.on('Assessment Result', { + refresh: function(frm) { + if (!frm.doc.__islocal) { + frm.trigger('setup_chart'); + } + }, + onload: function(frm) { frm.set_query('assessment_plan', function(){ return { @@ -15,7 +21,7 @@ frappe.ui.form.on("Assessment Result", { assessment_plan: function(frm) { if (frm.doc.assessment_plan) { frappe.call({ - method: "erpnext.education.api.get_assessment_details", + method: 'erpnext.education.api.get_assessment_details', args: { assessment_plan: frm.doc.assessment_plan }, @@ -23,40 +29,75 @@ frappe.ui.form.on("Assessment Result", { if (r.message) { frm.doc.details = []; $.each(r.message, function(i, d) { - var row = frappe.model.add_child(frm.doc, "Assessment Result Detail", "details"); + var row = frappe.model.add_child(frm.doc, 'Assessment Result Detail', 'details'); row.assessment_criteria = d.assessment_criteria; row.maximum_score = d.maximum_score; }); } - refresh_field("details"); + refresh_field('details'); } }); } + }, + + setup_chart: function(frm) { + let labels = []; + let maximum_scores = []; + let scores = []; + $.each(frm.doc.details, function(_i, e) { + labels.push(e.assessment_criteria); + maximum_scores.push(e.maximum_score); + scores.push(e.score); + }); + + if (labels.length && maximum_scores.length && scores.length) { + frm.dashboard.chart_area.empty().removeClass('hidden'); + new frappe.Chart('.form-graph', { + title: 'Assessment Results', + data: { + labels: labels, + datasets: [ + { + name: 'Maximum Score', + chartType: 'bar', + values: maximum_scores, + }, + { + name: 'Score Obtained', + chartType: 'bar', + values: scores, + } + ] + }, + colors: ['#4CA746', '#98D85B'], + type: 'bar' + }); + } } }); -frappe.ui.form.on("Assessment Result Detail", { +frappe.ui.form.on('Assessment Result Detail', { score: function(frm, cdt, cdn) { var d = locals[cdt][cdn]; if(!d.maximum_score || !frm.doc.grading_scale) { - d.score = ""; - frappe.throw(__("Please fill in all the details to generate Assessment Result.")); + d.score = ''; + frappe.throw(__('Please fill in all the details to generate Assessment Result.')); } if (d.score > d.maximum_score) { - frappe.throw(__("Score cannot be greater than Maximum Score")); + frappe.throw(__('Score cannot be greater than Maximum Score')); } else { frappe.call({ - method: "erpnext.education.api.get_grade", + method: 'erpnext.education.api.get_grade', args: { grading_scale: frm.doc.grading_scale, percentage: ((d.score/d.maximum_score) * 100) }, callback: function(r) { if (r.message) { - frappe.model.set_value(cdt, cdn, "grade", r.message); + frappe.model.set_value(cdt, cdn, 'grade', r.message); } } }); diff --git a/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py b/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py new file mode 100644 index 0000000000..438379d08e --- /dev/null +++ b/erpnext/education/doctype/assessment_result/assessment_result_dashboard.py @@ -0,0 +1,14 @@ +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'reports': [ + { + 'label': _('Reports'), + 'items': ['Final Assessment Grades', 'Course wise Assessment Report'] + } + ] + } \ No newline at end of file diff --git a/erpnext/education/doctype/course/course.js b/erpnext/education/doctype/course/course.js index 69329896e0..81e4a8c08d 100644 --- a/erpnext/education/doctype/course/course.js +++ b/erpnext/education/doctype/course/course.js @@ -1,41 +1,60 @@ -frappe.ui.form.on("Course", "refresh", function(frm) { - if(!cur_frm.doc.__islocal) { - frm.add_custom_button(__("Program"), function() { - frappe.route_options = { - "Program Course.course": frm.doc.name - } - frappe.set_route("List", "Program"); - }); +frappe.ui.form.on('Course', { + refresh: function(frm) { + if (!cur_frm.doc.__islocal) { + frm.add_custom_button(__('Add to Programs'), function() { + frm.trigger('add_course_to_programs') + }, __('Action')); + } - frm.add_custom_button(__("Student Group"), function() { - frappe.route_options = { - course: frm.doc.name + frm.set_query('default_grading_scale', function(){ + return { + filters: { + docstatus: 1 + } } - frappe.set_route("List", "Student Group"); }); + }, - frm.add_custom_button(__("Course Schedule"), function() { - frappe.route_options = { - course: frm.doc.name + add_course_to_programs: function(frm) { + get_programs_without_course(frm.doc.name).then(r => { + if (r.message.length) { + frappe.prompt([ + { + fieldname: 'programs', + label: __('Programs'), + fieldtype: 'MultiSelectPills', + get_data: function() { + return r.message; + } + }, + { + fieldtype: 'Check', + label: __('Is Mandatory'), + fieldname: 'mandatory', + } + ], + function(data) { + frappe.call({ + method: 'erpnext.education.doctype.course.course.add_course_to_programs', + args: { + 'course': frm.doc.name, + 'programs': data.programs, + 'mandatory': data.mandatory + }, + callback: function(r) { + if (!r.exc) { + frm.reload_doc(); + } + }, + freeze: true, + freeze_message: __('...Adding Course to Programs') + }) + }, __('Add Course to Programs'), __('Add')); + } else { + frappe.msgprint(__('This course is already added to the existing programs')); } - frappe.set_route("List", "Course Schedule"); - }); - - frm.add_custom_button(__("Assessment Plan"), function() { - frappe.route_options = { - course: frm.doc.name - } - frappe.set_route("List", "Assessment Plan"); }); } - - frm.set_query('default_grading_scale', function(){ - return { - filters: { - docstatus: 1 - } - } - }); }); frappe.ui.form.on('Course Topic', { @@ -50,3 +69,11 @@ frappe.ui.form.on('Course Topic', { }; } }); + +let get_programs_without_course = function(course) { + return frappe.call({ + type: 'GET', + method: 'erpnext.education.doctype.course.course.get_programs_without_course', + args: {'course': course} + }); +} \ No newline at end of file diff --git a/erpnext/education/doctype/course/course.py b/erpnext/education/doctype/course/course.py index 0747a22f8d..06efa54e77 100644 --- a/erpnext/education/doctype/course/course.py +++ b/erpnext/education/doctype/course/course.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import frappe +import json from frappe.model.document import Document from frappe import _ @@ -17,12 +18,39 @@ class Course(Document): for criteria in self.assessment_criteria: total_weightage += criteria.weightage or 0 if total_weightage != 100: - frappe.throw(_("Total Weightage of all Assessment Criteria must be 100%")) + frappe.throw(_('Total Weightage of all Assessment Criteria must be 100%')) def get_topics(self): topic_data= [] for topic in self.topics: - topic_doc = frappe.get_doc("Topic", topic.topic) + topic_doc = frappe.get_doc('Topic', topic.topic) if topic_doc.topic_content: topic_data.append(topic_doc) - return topic_data \ No newline at end of file + return topic_data + + +@frappe.whitelist() +def add_course_to_programs(course, programs, mandatory=False): + programs = json.loads(programs) + for entry in programs: + program = frappe.get_doc('Program', entry) + program.append('courses', { + 'course': course, + 'course_name': course, + 'mandatory': mandatory + }) + program.flags.ignore_mandatory = True + program.save() + frappe.db.commit() + frappe.msgprint(_('Course {0} has been added to all the selected programs successfully.').format(frappe.bold(course)), + title=_('Programs updated'), indicator='green') + +@frappe.whitelist() +def get_programs_without_course(course): + data = [] + for entry in frappe.db.get_all('Program'): + program = frappe.get_doc('Program', entry.name) + courses = [c.course for c in program.courses] + if not courses or course not in courses: + data.append(program.name) + return data \ No newline at end of file diff --git a/erpnext/education/doctype/course/course_dashboard.py b/erpnext/education/doctype/course/course_dashboard.py index 752af29a9d..8a570bdc57 100644 --- a/erpnext/education/doctype/course/course_dashboard.py +++ b/erpnext/education/doctype/course/course_dashboard.py @@ -6,12 +6,10 @@ from frappe import _ def get_data(): return { 'fieldname': 'course', - 'non_standard_fieldnames': { - }, 'transactions': [ { - 'label': _('Course'), - 'items': ['Course Enrollment', 'Course Schedule'] + 'label': _('Program and Course'), + 'items': ['Program', 'Course Enrollment', 'Course Schedule'] }, { 'label': _('Student'), @@ -19,7 +17,7 @@ def get_data(): }, { 'label': _('Assessment'), - 'items': ['Assessment Plan'] + 'items': ['Assessment Plan', 'Assessment Result'] }, ] } \ No newline at end of file diff --git a/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py b/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py new file mode 100644 index 0000000000..b9dd457b61 --- /dev/null +++ b/erpnext/education/doctype/course_enrollment/course_enrollment_dashboard.py @@ -0,0 +1,15 @@ +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'fieldname': 'enrollment', + 'transactions': [ + { + 'label': _('Activity'), + 'items': ['Course Activity', 'Quiz Activity'] + } + ] + } \ No newline at end of file diff --git a/erpnext/education/doctype/course_schedule/course_schedule.js b/erpnext/education/doctype/course_schedule/course_schedule.js index 692c2a8389..4275f6ef2a 100644 --- a/erpnext/education/doctype/course_schedule/course_schedule.js +++ b/erpnext/education/doctype/course_schedule/course_schedule.js @@ -4,13 +4,13 @@ cur_frm.add_fetch("student_group", "course", "course") frappe.ui.form.on("Course Schedule", { refresh: function(frm) { if (!frm.doc.__islocal) { - frm.add_custom_button(__("Attendance"), function() { + frm.add_custom_button(__("Mark Attendance"), function() { frappe.route_options = { based_on: "Course Schedule", course_schedule: frm.doc.name } frappe.set_route("Form", "Student Attendance Tool"); - }); + }).addClass("btn-primary"); } } }); \ No newline at end of file diff --git a/erpnext/education/doctype/course_schedule/course_schedule.json b/erpnext/education/doctype/course_schedule/course_schedule.json index 7346cab438..8c6746bda8 100644 --- a/erpnext/education/doctype/course_schedule/course_schedule.json +++ b/erpnext/education/doctype/course_schedule/course_schedule.json @@ -1,520 +1,520 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 0, - "autoname": "naming_series:", - "beta": 0, - "creation": "2015-09-09 16:34:04.960369", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 0, - "engine": "InnoDB", + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 1, + "allow_rename": 0, + "autoname": "naming_series:", + "beta": 0, + "creation": "2015-09-09 16:34:04.960369", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "Document", + "editable_grid": 0, + "engine": "InnoDB", "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "student_group", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Student Group", - "length": 0, - "no_copy": 0, - "options": "Student Group", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "student_group", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 1, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "Student Group", + "length": 0, + "no_copy": 0, + "options": "Student Group", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "instructor", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Instructor", - "length": 0, - "no_copy": 0, - "options": "Instructor", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "instructor", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 1, + "label": "Instructor", + "length": 0, + "no_copy": 0, + "options": "Instructor", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "instructor.Instructor_name", - "fieldname": "instructor_name", - "fieldtype": "Read Only", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Instructor Name", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_from": "instructor.Instructor_name", + "fieldname": "instructor_name", + "fieldtype": "Read Only", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 1, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Instructor Name", + "length": 0, + "no_copy": 0, + "options": "", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_2", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_2", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Naming Series", - "length": 0, - "no_copy": 0, - "options": "EDU-CSH-.YYYY.-", - "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": 1, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "", + "fieldname": "naming_series", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Naming Series", + "length": 0, + "no_copy": 0, + "options": "EDU-CSH-.YYYY.-", + "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": 1, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "course", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "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, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "course", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 1, + "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, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "color", - "fieldtype": "Color", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Color", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "color", + "fieldtype": "Color", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Color", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_6", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "section_break_6", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Today", - "fieldname": "schedule_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Schedule Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "Today", + "fieldname": "schedule_date", + "fieldtype": "Date", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Schedule Date", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "room", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Room", - "length": 0, - "no_copy": 0, - "options": "Room", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "room", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Room", + "length": 0, + "no_copy": 0, + "options": "Room", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_9", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "column_break_9", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "from_time", - "fieldtype": "Time", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "From Time", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "from_time", + "fieldtype": "Time", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "From Time", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "to_time", - "fieldtype": "Time", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "To Time", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "to_time", + "fieldtype": "Time", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "To Time", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "title", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Title", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "title", + "fieldtype": "Data", + "hidden": 1, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Title", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, "unique": 0 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "menu_index": 0, - "modified": "2018-08-21 14:44:51.827225", - "modified_by": "Administrator", - "module": "Education", - "name": "Course Schedule", - "name_case": "", - "owner": "Administrator", + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 0, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "menu_index": 0, + "modified": "2018-08-21 14:44:51.827225", + "modified_by": "Administrator", + "module": "Education", + "name": "Course Schedule", + "name_case": "", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Academics User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "amend": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "Academics User", + "set_user_permissions": 0, + "share": 1, + "submit": 0, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Education", - "show_name_in_global_search": 0, - "sort_field": "schedule_date", - "sort_order": "DESC", - "title_field": "title", - "track_changes": 0, - "track_seen": 0, + ], + "quick_entry": 0, + "read_only": 0, + "read_only_onload": 0, + "restrict_to_domain": "Education", + "show_name_in_global_search": 0, + "sort_field": "schedule_date", + "sort_order": "DESC", + "title_field": "title", + "track_changes": 0, + "track_seen": 0, "track_views": 0 } \ No newline at end of file diff --git a/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py b/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py new file mode 100644 index 0000000000..0866cd6535 --- /dev/null +++ b/erpnext/education/doctype/course_schedule/course_schedule_dashboard.py @@ -0,0 +1,15 @@ +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'fieldname': 'course_schedule', + 'transactions': [ + { + 'label': _('Attendance'), + 'items': ['Student Attendance'] + } + ] + } \ No newline at end of file diff --git a/erpnext/education/doctype/fee_schedule/fee_schedule.js b/erpnext/education/doctype/fee_schedule/fee_schedule.js index 13383312a8..75dd4469e8 100644 --- a/erpnext/education/doctype/fee_schedule/fee_schedule.js +++ b/erpnext/education/doctype/fee_schedule/fee_schedule.js @@ -3,13 +3,13 @@ frappe.ui.form.on('Fee Schedule', { setup: function(frm) { - frm.add_fetch("fee_structure", "receivable_account", "receivable_account"); - frm.add_fetch("fee_structure", "income_account", "income_account"); - frm.add_fetch("fee_structure", "cost_center", "cost_center"); + frm.add_fetch('fee_structure', 'receivable_account', 'receivable_account'); + frm.add_fetch('fee_structure', 'income_account', 'income_account'); + frm.add_fetch('fee_structure', 'cost_center', 'cost_center'); }, onload: function(frm) { - frm.set_query("receivable_account", function(doc) { + frm.set_query('receivable_account', function(doc) { return { filters: { 'account_type': 'Receivable', @@ -18,7 +18,8 @@ frappe.ui.form.on('Fee Schedule', { } }; }); - frm.set_query("income_account", function(doc) { + + frm.set_query('income_account', function(doc) { return { filters: { 'account_type': 'Income Account', @@ -27,57 +28,59 @@ frappe.ui.form.on('Fee Schedule', { } }; }); - frm.set_query("student_group", "student_groups", function() { + + frm.set_query('student_group', 'student_groups', function() { return { - "program": frm.doc.program, - "academic_term": frm.doc.academic_term, - "academic_year": frm.doc.academic_year, - "disabled": 0 + 'program': frm.doc.program, + 'academic_term': frm.doc.academic_term, + 'academic_year': frm.doc.academic_year, + 'disabled': 0 }; }); - frappe.realtime.on("fee_schedule_progress", function(data) { + + frappe.realtime.on('fee_schedule_progress', function(data) { if (data.reload && data.reload === 1) { frm.reload_doc(); } if (data.progress) { - let progress_bar = $(cur_frm.dashboard.progress_area).find(".progress-bar"); + let progress_bar = $(cur_frm.dashboard.progress_area).find('.progress-bar'); if (progress_bar) { - $(progress_bar).removeClass("progress-bar-danger").addClass("progress-bar-success progress-bar-striped"); - $(progress_bar).css("width", data.progress+"%"); + $(progress_bar).removeClass('progress-bar-danger').addClass('progress-bar-success progress-bar-striped'); + $(progress_bar).css('width', data.progress+'%'); } } }); }, refresh: function(frm) { - if(!frm.doc.__islocal && frm.doc.__onload && frm.doc.__onload.dashboard_info && - frm.doc.fee_creation_status=="Successful") { + if (!frm.doc.__islocal && frm.doc.__onload && frm.doc.__onload.dashboard_info && + frm.doc.fee_creation_status === 'Successful') { var info = frm.doc.__onload.dashboard_info; frm.dashboard.add_indicator(__('Total Collected: {0}', [format_currency(info.total_paid, info.currency)]), 'blue'); frm.dashboard.add_indicator(__('Total Outstanding: {0}', [format_currency(info.total_unpaid, info.currency)]), info.total_unpaid ? 'orange' : 'green'); } - if (frm.doc.fee_creation_status=="In Process") { - frm.dashboard.add_progress("Fee Creation Status", "0"); + if (frm.doc.fee_creation_status === 'In Process') { + frm.dashboard.add_progress('Fee Creation Status', '0'); } - if (frm.doc.docstatus==1 && !frm.doc.fee_creation_status || frm.doc.fee_creation_status == "Failed") { + if (frm.doc.docstatus === 1 && !frm.doc.fee_creation_status || frm.doc.fee_creation_status === 'Failed') { frm.add_custom_button(__('Create Fees'), function() { frappe.call({ - method: "create_fees", + method: 'create_fees', doc: frm.doc, callback: function() { frm.refresh(); } }); - }, "fa fa-play", "btn-success"); + }).addClass('btn-primary');; } - if (frm.doc.fee_creation_status == "Successful") { - frm.add_custom_button(__("View Fees Records"), function() { + if (frm.doc.fee_creation_status === 'Successful') { + frm.add_custom_button(__('View Fees Records'), function() { frappe.route_options = { fee_schedule: frm.doc.name }; - frappe.set_route("List", "Fees"); + frappe.set_route('List', 'Fees'); }); } @@ -86,35 +89,35 @@ frappe.ui.form.on('Fee Schedule', { fee_structure: function(frm) { if (frm.doc.fee_structure) { frappe.call({ - method: "erpnext.education.doctype.fee_schedule.fee_schedule.get_fee_structure", + method: 'erpnext.education.doctype.fee_schedule.fee_schedule.get_fee_structure', args: { - "target_doc": frm.doc.name, - "source_name": frm.doc.fee_structure + 'target_doc': frm.doc.name, + 'source_name': frm.doc.fee_structure }, callback: function(r) { var doc = frappe.model.sync(r.message); - frappe.set_route("Form", doc[0].doctype, doc[0].name); + frappe.set_route('Form', doc[0].doctype, doc[0].name); } }); } } }); -frappe.ui.form.on("Fee Schedule Student Group", { +frappe.ui.form.on('Fee Schedule Student Group', { student_group: function(frm, cdt, cdn) { var row = locals[cdt][cdn]; if (row.student_group && frm.doc.academic_year) { frappe.call({ - method: "erpnext.education.doctype.fee_schedule.fee_schedule.get_total_students", + method: 'erpnext.education.doctype.fee_schedule.fee_schedule.get_total_students', args: { - "student_group": row.student_group, - "academic_year": frm.doc.academic_year, - "academic_term": frm.doc.academic_term, - "student_category": frm.doc.student_category + 'student_group': row.student_group, + 'academic_year': frm.doc.academic_year, + 'academic_term': frm.doc.academic_term, + 'student_category': frm.doc.student_category }, callback: function(r) { - if(!r.exc) { - frappe.model.set_value(cdt, cdn, "total_students", r.message); + if (!r.exc) { + frappe.model.set_value(cdt, cdn, 'total_students', r.message); } } }); diff --git a/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py b/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py new file mode 100644 index 0000000000..acfe400219 --- /dev/null +++ b/erpnext/education/doctype/fee_schedule/fee_schedule_dashboard.py @@ -0,0 +1,13 @@ +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt +from __future__ import unicode_literals + +def get_data(): + return { + 'fieldname': 'fee_schedule', + 'transactions': [ + { + 'items': ['Fees'] + } + ] + } \ No newline at end of file diff --git a/erpnext/education/doctype/fee_structure/fee_structure.js b/erpnext/education/doctype/fee_structure/fee_structure.js index f09d2efcb9..b331c6d3c0 100644 --- a/erpnext/education/doctype/fee_structure/fee_structure.js +++ b/erpnext/education/doctype/fee_structure/fee_structure.js @@ -3,21 +3,21 @@ frappe.ui.form.on('Fee Structure', { setup: function(frm) { - frm.add_fetch("company", "default_receivable_account", "receivable_account"); - frm.add_fetch("company", "default_income_account", "income_account"); - frm.add_fetch("company", "cost_center", "cost_center"); + frm.add_fetch('company', 'default_receivable_account', 'receivable_account'); + frm.add_fetch('company', 'default_income_account', 'income_account'); + frm.add_fetch('company', 'cost_center', 'cost_center'); }, onload: function(frm) { - frm.set_query("academic_term", function() { + frm.set_query('academic_term', function() { return { - "filters": { - "academic_year": frm.doc.academic_year + 'filters': { + 'academic_year': frm.doc.academic_year } }; }); - frm.set_query("receivable_account", function(doc) { + frm.set_query('receivable_account', function(doc) { return { filters: { 'account_type': 'Receivable', @@ -26,7 +26,7 @@ frappe.ui.form.on('Fee Structure', { } }; }); - frm.set_query("income_account", function(doc) { + frm.set_query('income_account', function(doc) { return { filters: { 'account_type': 'Income Account', @@ -38,27 +38,27 @@ frappe.ui.form.on('Fee Structure', { }, refresh: function(frm) { - if(frm.doc.docstatus === 1) { + if (frm.doc.docstatus === 1) { frm.add_custom_button(__('Create Fee Schedule'), function() { frm.events.make_fee_schedule(frm); - }); + }).addClass('btn-primary'); } }, make_fee_schedule: function(frm) { frappe.model.open_mapped_doc({ - method: "erpnext.education.doctype.fee_structure.fee_structure.make_fee_schedule", + method: 'erpnext.education.doctype.fee_structure.fee_structure.make_fee_schedule', frm: frm }); } }); -frappe.ui.form.on("Fee Component", { +frappe.ui.form.on('Fee Component', { amount: function(frm) { var total_amount = 0; - for(var i=0;i { + if (!frm.doc.employee) return; + frappe.db.get_value("Employee", {name: frm.doc.employee}, "company", (d) => { frm.set_query("department", function() { return { "filters": { @@ -22,30 +22,16 @@ frappe.ui.form.on("Instructor", { }); }, refresh: function(frm) { - if(!frm.doc.__islocal) { - frm.add_custom_button(__("Student Group"), function() { - frappe.route_options = { - instructor: frm.doc.name - } - frappe.set_route("List", "Student Group"); - }); - frm.add_custom_button(__("Course Schedule"), function() { - frappe.route_options = { - instructor: frm.doc.name - } - frappe.set_route("List", "Course Schedule"); - }); + if (!frm.doc.__islocal) { frm.add_custom_button(__("As Examiner"), function() { - frappe.route_options = { + frappe.new_doc("Assessment Plan", { examiner: frm.doc.name - } - frappe.set_route("List", "Assessment Plan"); + }); }, __("Assessment Plan")); frm.add_custom_button(__("As Supervisor"), function() { - frappe.route_options = { + frappe.new_doc("Assessment Plan", { supervisor: frm.doc.name - } - frappe.set_route("List", "Assessment Plan"); + }); }, __("Assessment Plan")); } frm.set_query("employee", function(doc) { diff --git a/erpnext/education/doctype/instructor/instructor.py b/erpnext/education/doctype/instructor/instructor.py index 28df2fcdc1..b1bfcbb2f1 100644 --- a/erpnext/education/doctype/instructor/instructor.py +++ b/erpnext/education/doctype/instructor/instructor.py @@ -30,4 +30,14 @@ class Instructor(Document): if self.employee and frappe.db.get_value("Instructor", {'employee': self.employee, 'name': ['!=', self.name]}, 'name'): frappe.throw(_("Employee ID is linked with another instructor")) - +def get_timeline_data(doctype, name): + """Return timeline for course schedule""" + return dict(frappe.db.sql( + """ + SELECT unix_timestamp(`schedule_date`), count(*) + FROM `tabCourse Schedule` + WHERE + instructor=%s and + `schedule_date` > date_sub(curdate(), interval 1 year) + GROUP BY schedule_date + """, name)) diff --git a/erpnext/education/doctype/instructor/instructor_dashboard.py b/erpnext/education/doctype/instructor/instructor_dashboard.py new file mode 100644 index 0000000000..a404fc56c5 --- /dev/null +++ b/erpnext/education/doctype/instructor/instructor_dashboard.py @@ -0,0 +1,24 @@ +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'heatmap': True, + 'heatmap_message': _('This is based on the course schedules of this Instructor'), + 'fieldname': 'instructor', + 'non_standard_fieldnames': { + 'Assessment Plan': 'supervisor' + }, + 'transactions': [ + { + 'label': _('Course and Assessment'), + 'items': ['Course Schedule', 'Assessment Plan'] + }, + { + 'label': _('Students'), + 'items': ['Student Group'] + } + ] + } \ No newline at end of file diff --git a/erpnext/education/doctype/program/program_dashboard.py b/erpnext/education/doctype/program/program_dashboard.py index cb8f74207e..c5d249451f 100644 --- a/erpnext/education/doctype/program/program_dashboard.py +++ b/erpnext/education/doctype/program/program_dashboard.py @@ -10,11 +10,15 @@ def get_data(): }, { 'label': _('Student Activity'), - 'items': ['Student Group' ] + 'items': ['Student Group', 'Student Log'] }, { 'label': _('Fee'), - 'items': ['Fees','Fee Structure'] + 'items': ['Fees','Fee Structure', 'Fee Schedule'] + }, + { + 'label': _('Assessment'), + 'items': ['Assessment Plan', 'Assessment Result'] } ] } \ No newline at end of file diff --git a/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py b/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py new file mode 100644 index 0000000000..18d307cdf0 --- /dev/null +++ b/erpnext/education/doctype/program_enrollment/program_enrollment_dashboard.py @@ -0,0 +1,19 @@ +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'fieldname': 'program_enrollment', + 'transactions': [ + { + 'label': _('Course and Fee'), + 'items': ['Course Enrollment', 'Fees'] + } + ], + 'reports': [ + { + 'label': _('Report'), + 'items': ['Student and Guardian Contact Details'] + } + ] + } \ No newline at end of file diff --git a/erpnext/education/doctype/quiz/quiz.js b/erpnext/education/doctype/quiz/quiz.js index 7b870886ec..01bcf73236 100644 --- a/erpnext/education/doctype/quiz/quiz.js +++ b/erpnext/education/doctype/quiz/quiz.js @@ -3,11 +3,17 @@ frappe.ui.form.on('Quiz', { refresh: function(frm) { - + if (!frm.doc.__islocal) { + frm.add_custom_button(__('Add to Topics'), function() { + frm.trigger('add_quiz_to_topics'); + }, __('Action')); + } }, + validate: function(frm){ frm.events.check_duplicate_question(frm.doc.question); }, + check_duplicate_question: function(questions_data){ var questions = []; questions_data.forEach(function(q){ @@ -15,7 +21,51 @@ frappe.ui.form.on('Quiz', { }); var questions_set = new Set(questions); if (questions.length != questions_set.size) { - frappe.throw(__("The question cannot be duplicate")); + frappe.throw(__('The question cannot be duplicate')); } + }, + + add_quiz_to_topics: function(frm) { + get_topics_without_quiz(frm.doc.name).then(r => { + if (r.message.length) { + frappe.prompt([ + { + fieldname: 'topics', + label: __('Topics'), + fieldtype: 'MultiSelectPills', + get_data: function() { + return r.message; + } + } + ], + function(data) { + frappe.call({ + method: 'erpnext.education.doctype.topic.topic.add_content_to_topics', + args: { + 'content_type': 'Quiz', + 'content': frm.doc.name, + 'topics': data.topics, + }, + callback: function(r) { + if (!r.exc) { + frm.reload_doc(); + } + }, + freeze: true, + freeze_message: __('...Adding Quiz to Topics') + }); + }, __('Add Quiz to Topics'), __('Add')); + } else { + frappe.msgprint(__('This quiz is already added to the existing topics')); + } + }); } -}); \ No newline at end of file +}); + +let get_topics_without_quiz = function(quiz) { + return frappe.call({ + type: 'GET', + method: 'erpnext.education.doctype.quiz.quiz.get_topics_without_quiz', + args: {'quiz': quiz} + }); +}; \ No newline at end of file diff --git a/erpnext/education/doctype/quiz/quiz.py b/erpnext/education/doctype/quiz/quiz.py index ae1cb6ce42..a774b88579 100644 --- a/erpnext/education/doctype/quiz/quiz.py +++ b/erpnext/education/doctype/quiz/quiz.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import frappe +import json from frappe import _ from frappe.model.document import Document @@ -59,3 +60,12 @@ def compare_list_elementwise(*args): except TypeError: frappe.throw(_("Compare List function takes on list arguments")) +@frappe.whitelist() +def get_topics_without_quiz(quiz): + data = [] + for entry in frappe.db.get_all('Topic'): + topic = frappe.get_doc('Topic', entry.name) + topic_contents = [tc.content for tc in topic.topic_content] + if not topic_contents or quiz not in topic_contents: + data.append(topic.name) + return data \ No newline at end of file diff --git a/erpnext/education/doctype/room/room.js b/erpnext/education/doctype/room/room.js index 032db9835b..20cee6b2a6 100644 --- a/erpnext/education/doctype/room/room.js +++ b/erpnext/education/doctype/room/room.js @@ -1,10 +1,2 @@ -frappe.ui.form.on("Room", "refresh", function(frm) { - if(!cur_frm.doc.__islocal) { - frm.add_custom_button(__("Course Schedule"), function() { - frappe.route_options = { - room: frm.doc.name - } - frappe.set_route("List", "Course Schedule"); - }); - } +frappe.ui.form.on("Room", { }); \ No newline at end of file diff --git a/erpnext/education/doctype/room/room_dashboard.py b/erpnext/education/doctype/room/room_dashboard.py new file mode 100644 index 0000000000..99aac3393e --- /dev/null +++ b/erpnext/education/doctype/room/room_dashboard.py @@ -0,0 +1,19 @@ +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'fieldname': 'room', + 'transactions': [ + { + 'label': _('Course'), + 'items': ['Course Schedule'] + }, + { + 'label': _('Assessment'), + 'items': ['Assessment Plan'] + } + ] + } \ No newline at end of file diff --git a/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py b/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py new file mode 100644 index 0000000000..9c41b8f3dc --- /dev/null +++ b/erpnext/education/doctype/student_attendance/student_attendance_dashboard.py @@ -0,0 +1,12 @@ +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'reports': [ + { + 'label': _('Reports'), + 'items': ['Student Monthly Attendance Sheet', 'Student Batch-Wise Attendance'] + } + ] + } \ No newline at end of file diff --git a/erpnext/education/doctype/student_category/student_category_dashboard.py b/erpnext/education/doctype/student_category/student_category_dashboard.py new file mode 100644 index 0000000000..f31c34bd94 --- /dev/null +++ b/erpnext/education/doctype/student_category/student_category_dashboard.py @@ -0,0 +1,13 @@ +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'fieldname': 'student_category', + 'transactions': [ + { + 'label': _('Fee'), + 'items': ['Fee Structure', 'Fee Schedule', 'Fees'] + } + ] + } diff --git a/erpnext/education/doctype/student_group/student_group.js b/erpnext/education/doctype/student_group/student_group.js index 13724409ba..51e3b74a5c 100644 --- a/erpnext/education/doctype/student_group/student_group.js +++ b/erpnext/education/doctype/student_group/student_group.js @@ -1,18 +1,18 @@ -cur_frm.add_fetch("student", "title", "student_name"); +cur_frm.add_fetch('student', 'title', 'student_name'); -frappe.ui.form.on("Student Group", { +frappe.ui.form.on('Student Group', { onload: function(frm) { - frm.set_query("academic_term", function() { + frm.set_query('academic_term', function() { return { - "filters": { - "academic_year": (frm.doc.academic_year) + filters: { + 'academic_year': (frm.doc.academic_year) } }; }); if (!frm.__islocal) { - frm.set_query("student", "students", function() { + frm.set_query('student', 'students', function() { return{ - query: "erpnext.education.doctype.student_group.student_group.fetch_students", + query: 'erpnext.education.doctype.student_group.student_group.fetch_students', filters: { 'academic_year': frm.doc.academic_year, 'group_based_on': frm.doc.group_based_on, @@ -30,87 +30,86 @@ frappe.ui.form.on("Student Group", { refresh: function(frm) { if (!frm.doc.__islocal) { - frm.add_custom_button(__("Attendance"), function() { - frappe.route_options = { - based_on: "Student Group", - student_group: frm.doc.name - } - frappe.set_route("List", "Student Attendance Tool"); - }); - frm.add_custom_button(__("Course Schedule"), function() { - frappe.route_options = { - student_group: frm.doc.name - } - frappe.set_route("List", "Course Schedule"); - }); - frm.add_custom_button(__("Assessment Plan"), function() { - frappe.route_options = { - student_group: frm.doc.name - } - frappe.set_route("List", "Assessment Plan"); - }); - frm.add_custom_button(__("Update Email Group"), function() { + + frm.add_custom_button(__('Add Guardians to Email Group'), function() { frappe.call({ - method: "erpnext.education.api.update_email_group", + method: 'erpnext.education.api.update_email_group', args: { - "doctype": "Student Group", - "name": frm.doc.name + 'doctype': 'Student Group', + 'name': frm.doc.name } }); - }); - frm.add_custom_button(__("Newsletter"), function() { + }, __('Actions')); + + frm.add_custom_button(__('Student Attendance Tool'), function() { frappe.route_options = { - "Newsletter Email Group.email_group": frm.doc.name + based_on: 'Student Group', + student_group: frm.doc.name } - frappe.set_route("List", "Newsletter"); - }); + frappe.set_route('Form', 'Student Attendance Tool', 'Student Attendance Tool'); + }, __('Tools')); + + frm.add_custom_button(__('Course Scheduling Tool'), function() { + frappe.route_options = { + student_group: frm.doc.name + } + frappe.set_route('Form', 'Course Scheduling Tool', 'Course Scheduling Tool'); + }, __('Tools')); + + frm.add_custom_button(__('Newsletter'), function() { + frappe.route_options = { + 'Newsletter Email Group.email_group': frm.doc.name + } + frappe.set_route('List', 'Newsletter'); + }, __('View')); + } }, - + group_based_on: function(frm) { - if (frm.doc.group_based_on == "Batch") { + if (frm.doc.group_based_on == 'Batch') { frm.doc.course = null; frm.set_df_property('program', 'reqd', 1); frm.set_df_property('course', 'reqd', 0); } - else if (frm.doc.group_based_on == "Course") { + else if (frm.doc.group_based_on == 'Course') { frm.set_df_property('program', 'reqd', 0); frm.set_df_property('course', 'reqd', 1); } - else if (frm.doc.group_based_on == "Activity") { + else if (frm.doc.group_based_on == 'Activity') { frm.set_df_property('program', 'reqd', 0); frm.set_df_property('course', 'reqd', 0); } }, get_students: function(frm) { - if (frm.doc.group_based_on == "Batch" || frm.doc.group_based_on == "Course") { + if (frm.doc.group_based_on == 'Batch' || frm.doc.group_based_on == 'Course') { var student_list = []; var max_roll_no = 0; - $.each(frm.doc.students, function(i,d) { + $.each(frm.doc.students, function(_i,d) { student_list.push(d.student); if (d.group_roll_number>max_roll_no) { max_roll_no = d.group_roll_number; } }); - if(frm.doc.academic_year) { + if (frm.doc.academic_year) { frappe.call({ - method: "erpnext.education.doctype.student_group.student_group.get_students", + method: 'erpnext.education.doctype.student_group.student_group.get_students', args: { - "academic_year": frm.doc.academic_year, - "academic_term": frm.doc.academic_term, - "group_based_on": frm.doc.group_based_on, - "program": frm.doc.program, - "batch" : frm.doc.batch, - "student_category" : frm.doc.student_category, - "course": frm.doc.course + 'academic_year': frm.doc.academic_year, + 'academic_term': frm.doc.academic_term, + 'group_based_on': frm.doc.group_based_on, + 'program': frm.doc.program, + 'batch' : frm.doc.batch, + 'student_category' : frm.doc.student_category, + 'course': frm.doc.course }, callback: function(r) { - if(r.message) { + if (r.message) { $.each(r.message, function(i, d) { if(!in_list(student_list, d.student)) { - var s = frm.add_child("students"); + var s = frm.add_child('students'); s.student = d.student; s.student_name = d.student_name; if (d.active === 0) { @@ -119,16 +118,16 @@ frappe.ui.form.on("Student Group", { s.group_roll_number = ++max_roll_no; } }); - refresh_field("students"); + refresh_field('students'); frm.save(); } else { - frappe.msgprint(__("Student Group is already updated.")) + frappe.msgprint(__('Student Group is already updated.')) } } }) } } else { - frappe.msgprint(__("Select students manually for the Activity based Group")); + frappe.msgprint(__('Select students manually for the Activity based Group')); } } }); diff --git a/erpnext/education/doctype/student_group/student_group_dashboard.py b/erpnext/education/doctype/student_group/student_group_dashboard.py new file mode 100644 index 0000000000..ad7a6de7b3 --- /dev/null +++ b/erpnext/education/doctype/student_group/student_group_dashboard.py @@ -0,0 +1,19 @@ +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'fieldname': 'student_group', + 'transactions': [ + { + 'label': _('Assessment'), + 'items': ['Assessment Plan', 'Assessment Result'] + }, + { + 'label': _('Course'), + 'items': ['Course Schedule'] + } + ] + } \ No newline at end of file diff --git a/erpnext/education/doctype/topic/topic.js b/erpnext/education/doctype/topic/topic.js index 695c17476c..2002b0c8e3 100644 --- a/erpnext/education/doctype/topic/topic.js +++ b/erpnext/education/doctype/topic/topic.js @@ -3,6 +3,53 @@ frappe.ui.form.on('Topic', { refresh: function(frm) { + if (!cur_frm.doc.__islocal) { + frm.add_custom_button(__('Add to Courses'), function() { + frm.trigger('add_topic_to_courses'); + }, __('Action')); + } + }, + add_topic_to_courses: function(frm) { + get_courses_without_topic(frm.doc.name).then(r => { + if (r.message.length) { + frappe.prompt([ + { + fieldname: 'courses', + label: __('Courses'), + fieldtype: 'MultiSelectPills', + get_data: function() { + return r.message; + } + } + ], + function(data) { + frappe.call({ + method: 'erpnext.education.doctype.topic.topic.add_topic_to_courses', + args: { + 'topic': frm.doc.name, + 'courses': data.courses + }, + callback: function(r) { + if (!r.exc) { + frm.reload_doc(); + } + }, + freeze: true, + freeze_message: __('...Adding Topic to Courses') + }); + }, __('Add Topic to Courses'), __('Add')); + } else { + frappe.msgprint(__('This topic is already added to the existing courses')); + } + }); } }); + +let get_courses_without_topic = function(topic) { + return frappe.call({ + type: 'GET', + method: 'erpnext.education.doctype.topic.topic.get_courses_without_topic', + args: {'topic': topic} + }); +}; \ No newline at end of file diff --git a/erpnext/education/doctype/topic/topic.py b/erpnext/education/doctype/topic/topic.py index 7e5da329eb..a5253e9329 100644 --- a/erpnext/education/doctype/topic/topic.py +++ b/erpnext/education/doctype/topic/topic.py @@ -4,6 +4,8 @@ from __future__ import unicode_literals import frappe +import json +from frappe import _ from frappe.model.document import Document class Topic(Document): @@ -14,4 +16,44 @@ class Topic(Document): except Exception as e: frappe.log_error(frappe.get_traceback()) return None - return content_data \ No newline at end of file + return content_data + +@frappe.whitelist() +def get_courses_without_topic(topic): + data = [] + for entry in frappe.db.get_all('Course'): + course = frappe.get_doc('Course', entry.name) + topics = [t.topic for t in course.topics] + if not topics or topic not in topics: + data.append(course.name) + return data + +@frappe.whitelist() +def add_topic_to_courses(topic, courses, mandatory=False): + courses = json.loads(courses) + for entry in courses: + course = frappe.get_doc('Course', entry) + course.append('topics', { + 'topic': topic, + 'topic_name': topic + }) + course.flags.ignore_mandatory = True + course.save() + frappe.db.commit() + frappe.msgprint(_('Topic {0} has been added to all the selected courses successfully.').format(frappe.bold(topic)), + title=_('Courses updated'), indicator='green') + +@frappe.whitelist() +def add_content_to_topics(content_type, content, topics): + topics = json.loads(topics) + for entry in topics: + topic = frappe.get_doc('Topic', entry) + topic.append('topic_content', { + 'content_type': content_type, + 'content': content, + }) + topic.flags.ignore_mandatory = True + topic.save() + frappe.db.commit() + frappe.msgprint(_('{0} {1} has been added to all the selected topics successfully.').format(content_type, frappe.bold(content)), + title=_('Topics updated'), indicator='green') \ No newline at end of file