diff --git a/lms/lms/doctype/lms_batch/lms_batch.js b/lms/lms/doctype/lms_batch/lms_batch.js index 1a95c493..34f9d503 100644 --- a/lms/lms/doctype/lms_batch/lms_batch.js +++ b/lms/lms/doctype/lms_batch/lms_batch.js @@ -52,6 +52,7 @@ const set_timetable = (frm) => { "start_time", "end_time", "duration", + "milestone", ], filters: { parent: frm.doc.timetable_template, @@ -82,6 +83,7 @@ const add_timetable_rows = (frm, timetable) => { .format("HH:mm") : null; child.duration = row.duration; + child.milestone = row.milestone; }); frm.refresh_field("timetable"); diff --git a/lms/lms/doctype/lms_batch/lms_batch.py b/lms/lms/doctype/lms_batch/lms_batch.py index 828ef2f9..ea368a7e 100644 --- a/lms/lms/doctype/lms_batch/lms_batch.py +++ b/lms/lms/doctype/lms_batch/lms_batch.py @@ -12,9 +12,6 @@ from frappe.utils import ( cint, format_date, format_datetime, - add_to_date, - getdate, - get_datetime, ) from lms.lms.utils import get_lessons, get_lesson_index, get_lesson_url from lms.www.utils import get_quiz_details, get_assignment_details @@ -325,7 +322,17 @@ def get_batch_timetable(batch): timetable = frappe.get_all( "LMS Batch Timetable", filters={"parent": batch}, - fields=["reference_doctype", "reference_docname", "date", "start_time", "end_time"], + fields=[ + "reference_doctype", + "reference_docname", + "date", + "start_time", + "end_time", + "milestone", + "name", + "idx", + "parent", + ], order_by="date", ) @@ -362,22 +369,65 @@ def get_timetable_details(timetable): assessment = frappe._dict({"assessment_name": entry.reference_docname}) if entry.reference_doctype == "Course Lesson": - entry.icon = "icon-list" course = frappe.db.get_value( entry.reference_doctype, entry.reference_docname, "course" ) entry.url = get_lesson_url(course, get_lesson_index(entry.reference_docname)) + entry.completed = ( + True + if frappe.db.exists( + "LMS Course Progress", + {"lesson": entry.reference_docname, "member": frappe.session.user}, + ) + else False + ) + elif entry.reference_doctype == "LMS Quiz": - entry.icon = "icon-quiz" entry.url = "/quizzes" details = get_quiz_details(assessment, frappe.session.user) entry.update(details) elif entry.reference_doctype == "LMS Assignment": - entry.icon = "icon-quiz" details = get_assignment_details(assessment, frappe.session.user) entry.update(details) timetable = sorted(timetable, key=lambda k: k["date"]) return timetable + + +@frappe.whitelist() +def is_milestone_complete(idx, batch): + previous_rows = frappe.get_all( + "LMS Batch Timetable", + filters={"parent": batch, "idx": ["<", cint(idx)]}, + fields=["reference_doctype", "reference_docname", "idx"], + order_by="idx", + ) + + for row in previous_rows: + if row.reference_doctype == "Course Lesson": + if not frappe.db.exists( + "LMS Course Progress", + {"member": frappe.session.user, "lesson": row.reference_docname}, + ): + return False + + if row.reference_doctype == "LMS Quiz": + passing_percentage = frappe.db.get_value( + row.reference_doctype, row.reference_docname, "passing_percentage" + ) + if not frappe.db.exists( + "LMS Quiz Submission", + {"quiz": row.reference_docname, "member": frappe.session.user}, + ): + return False + + if row.reference_doctype == "LMS Assignment": + if not frappe.db.exists( + "LMS Assignment Submission", + {"assignment": row.reference_docname, "member": frappe.session.user}, + ): + return False + + return True diff --git a/lms/lms/doctype/lms_batch_timetable/lms_batch_timetable.json b/lms/lms/doctype/lms_batch_timetable/lms_batch_timetable.json index 4ab57d2e..cbf51bd8 100644 --- a/lms/lms/doctype/lms_batch_timetable/lms_batch_timetable.json +++ b/lms/lms/doctype/lms_batch_timetable/lms_batch_timetable.json @@ -16,7 +16,8 @@ "column_break_merq", "start_time", "end_time", - "duration" + "duration", + "milestone" ], "fields": [ { @@ -69,12 +70,17 @@ "fieldname": "day", "fieldtype": "Int", "label": "Day" + }, + { + "fieldname": "milestone", + "fieldtype": "Check", + "label": "Milestone" } ], "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2023-10-03 17:40:31.530181", + "modified": "2023-10-20 11:58:01.782921", "modified_by": "Administrator", "module": "LMS", "name": "LMS Batch Timetable", diff --git a/lms/lms/doctype/lms_quiz/lms_quiz.py b/lms/lms/doctype/lms_quiz/lms_quiz.py index 13075e6f..709cfe34 100644 --- a/lms/lms/doctype/lms_quiz/lms_quiz.py +++ b/lms/lms/doctype/lms_quiz/lms_quiz.py @@ -65,7 +65,6 @@ def quiz_summary(quiz, results): correct = result["is_correct"][0] for point in result["is_correct"]: correct = correct and point - result["is_correct"] = correct question_details = frappe.db.get_value( @@ -100,6 +99,8 @@ def quiz_summary(quiz, results): "score": score, "score_out_of": score_out_of, "member": frappe.session.user, + "percentage": percentage, + "passing_percentage": quiz_details.passing_percentage, } ) submission.save(ignore_permissions=True) diff --git a/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json b/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json index 735d87a0..84d63e77 100644 --- a/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json +++ b/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.json @@ -15,6 +15,7 @@ "score_out_of", "column_break_gkip", "percentage", + "passing_percentage", "section_break_6", "result" ], @@ -96,12 +97,20 @@ "non_negative": 1, "read_only": 1, "reqd": 1 + }, + { + "fieldname": "passing_percentage", + "fieldtype": "Int", + "label": "Passing Percentage", + "non_negative": 1, + "read_only": 1, + "reqd": 1 } ], "in_create": 1, "index_web_pages_for_search": 1, "links": [], - "modified": "2023-10-17 13:07:27.979974", + "modified": "2023-10-17 13:07:27.979975", "modified_by": "Administrator", "module": "LMS", "name": "LMS Quiz Submission", diff --git a/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.py b/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.py index e481d57e..9d7050d5 100644 --- a/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.py +++ b/lms/lms/doctype/lms_quiz_submission/lms_quiz_submission.py @@ -7,7 +7,8 @@ from frappe.model.document import Document class LMSQuizSubmission(Document): def before_insert(self): - self.set_percentage() + if not self.percentage: + self.set_percentage() def set_percentage(self): if self.score and self.score_out_of: diff --git a/lms/www/batches/batch.js b/lms/www/batches/batch.js index be3ea75d..74395a2b 100644 --- a/lms/www/batches/batch.js +++ b/lms/www/batches/batch.js @@ -686,7 +686,9 @@ const get_calendar_options = (element, calendar_id) => { ], template: { time: function (event) { + let hide = event.raw.completed ? "" : "hide"; return `
+
${frappe.datetime.get_time(event.start.d.d)} - ${frappe.datetime.get_time(event.end.d.d)}
${event.title}
@@ -717,6 +719,11 @@ const create_events = (calendar, events, calendar_id) => { }, raw: { url: event.url, + milestone: event.milestone, + name: event.name, + idx: event.idx, + parent: event.parent, + completed: event.completed, }, }); }); @@ -730,9 +737,28 @@ const add_links_to_events = (calendar) => { event_date = moment(event_date).format("YYYY-MM-DD"); let current_date = moment().format("YYYY-MM-DD"); - if (allow_future || moment(event_date).isSameOrBefore(current_date)) { - window.open(event.raw.url, "_blank"); - } + + if (!moment(event_date).isSameOrBefore(current_date) && !allow_future) + return; + + if (event.raw.milestone) { + frappe.call({ + method: "lms.lms.doctype.lms_batch.lms_batch.is_milestone_complete", + args: { + idx: event.raw.idx, + batch: event.raw.parent, + }, + callback: (data) => { + if (data.message) window.open(event.raw.url, "_blank"); + else + frappe.show_alert({ + message: + "Please complete all previous activities to proceed.", + indicator: "red", + }); + }, + }); + } else window.open(event.raw.url, "_blank"); }); }; @@ -755,17 +781,13 @@ const set_calendar_range = (calendar, events) => { ).format("DD MMMM YYYY")}` ); - if (week_start.diff(moment(events[0].date), "days") <= 0) { + if (week_start.diff(moment(events[0].date), "days") <= 0) $("#prev-week").hide(); - } else { - $("#prev-week").show(); - } + else $("#prev-week").show(); - if (week_end.diff(moment(events.slice(-1)[0].date), "days") > 0) { + if (week_end.diff(moment(events.slice(-1)[0].date), "days") > 0) $("#next-week").hide(); - } else { - $("#next-week").show(); - } + else $("#next-week").show(); }; const get_background_color = (doctype) => { diff --git a/lms/www/utils.py b/lms/www/utils.py index b44c6aec..aa4a1356 100644 --- a/lms/www/utils.py +++ b/lms/www/utils.py @@ -93,7 +93,7 @@ def get_assignment_details(assessment, member): "assignment": assessment.assessment_name, } ) - + assessment.completed = False if existing_submission: assessment.submission = frappe.db.get_value( "LMS Assignment Submission", @@ -101,6 +101,7 @@ def get_assignment_details(assessment, member): ["name", "status", "comments"], as_dict=True, ) + assessment.completed = True assessment.edit_url = f"/assignments/{assessment.assessment_name}" submission_name = existing_submission if existing_submission else "new-submission" @@ -112,7 +113,10 @@ def get_assignment_details(assessment, member): def get_quiz_details(assessment, member): - assessment.title = frappe.db.get_value("LMS Quiz", assessment.assessment_name, "title") + assessment_details = frappe.db.get_value( + "LMS Quiz", assessment.assessment_name, ["title", "passing_percentage"], as_dict=1 + ) + assessment.title = assessment_details.title existing_submission = frappe.get_all( "LMS Quiz Submission", @@ -120,13 +124,17 @@ def get_quiz_details(assessment, member): "member": member, "quiz": assessment.assessment_name, }, - ["name", "score"], - order_by="creation desc", + ["name", "score", "percentage"], + order_by="percentage desc", ) if len(existing_submission): assessment.submission = existing_submission[0] + assessment.completed = False + if assessment.submission: + assessment.completed = True + assessment.edit_url = f"/quizzes/{assessment.assessment_name}" submission_name = ( existing_submission[0].name if len(existing_submission) else "new-submission"