diff --git a/frontend/src/pages/SCORMChapter.vue b/frontend/src/pages/SCORMChapter.vue index fed85dbe..ed3d51bb 100644 --- a/frontend/src/pages/SCORMChapter.vue +++ b/frontend/src/pages/SCORMChapter.vue @@ -86,25 +86,35 @@ const enrollment = createListResource({ }) const getDataFromLMS = (key) => { - if (key == 'cmi.core.lesson_status') { - if (progress.data?.status == 'Complete') { - return 'passed' - } - return 'incomplete' + if (key === 'cmi.core.lesson_status') { + return progress.data?.status === 'Complete' ? 'passed' : 'incomplete' + } else if (key === 'cmi.launch_data') { + return progress.data?.scorm_content || '' + } else if (key === 'cmi.suspend_data') { + return progress.data?.scorm_content || '' } return '' } const saveDataToLMS = (key, value) => { - if (key == 'cmi.core.lesson_status' && value == 'passed') { - saveProgress() + if (key === 'cmi.core.lesson_status' && value === 'passed') { + saveProgress({ + is_complete: true, + scorm_content: '', + }) + } else if (key === 'cmi.suspend_data') { + saveProgress({ + is_complete: false, + scorm_content: value, + }) } } -const saveProgress = () => { +const saveProgress = (scormDetails = null) => { call('lms.lms.doctype.course_lesson.course_lesson.save_progress', { lesson: chapter.doc.lessons[0].lesson, course: props.courseName, + scorm_details: scormDetails, }) } @@ -113,7 +123,7 @@ const progress = createResource({ makeParams(values) { return { doctype: 'LMS Course Progress', - fieldname: 'status', + fieldname: ['status', 'scorm_content'], filters: { member: user.data?.name, lesson: chapter.doc.lessons[0].lesson, diff --git a/lms/lms/doctype/course_lesson/course_lesson.py b/lms/lms/doctype/course_lesson/course_lesson.py index 4057a2ab..a35b16e7 100644 --- a/lms/lms/doctype/course_lesson/course_lesson.py +++ b/lms/lms/doctype/course_lesson/course_lesson.py @@ -8,6 +8,7 @@ from frappe.utils.telemetry import capture from lms.lms.utils import get_course_progress from ...md import find_macros import json +from pydantic import BaseModel class CourseLesson(Document): @@ -73,8 +74,16 @@ class CourseLesson(Document): return [frappe.get_doc("LMS Exercise", name) for name in exercises] +class SCORMDetails(BaseModel): + is_complete: bool + scorm_content: str | None = None + + @frappe.whitelist() -def save_progress(lesson, course): +def save_progress(lesson: str, course: str, scorm_details: SCORMDetails | None = None): + """ + Note: Pass the argument scorm_details only if it is SCORM related save_progress + """ membership = frappe.db.exists( "LMS Enrollment", {"course": course, "member": frappe.session.user} ) @@ -82,14 +91,23 @@ def save_progress(lesson, course): return 0 frappe.db.set_value("LMS Enrollment", membership, "current_lesson", lesson) - already_completed = frappe.db.exists( + progress_already_exists = frappe.db.exists( "LMS Course Progress", {"lesson": lesson, "member": frappe.session.user} ) + lesson_already_completed = frappe.db.exists( + "LMS Course Progress", + {"lesson": lesson, "member": frappe.session.user, "status": "Complete"}, + ) quiz_completed = get_quiz_progress(lesson) assignment_completed = get_assignment_progress(lesson) - if not already_completed and quiz_completed and assignment_completed: + if ( + not progress_already_exists + and quiz_completed + and assignment_completed + and not scorm_details + ): frappe.get_doc( { "doctype": "LMS Course Progress", @@ -98,6 +116,29 @@ def save_progress(lesson, course): "member": frappe.session.user, } ).save(ignore_permissions=True) + elif scorm_details and not lesson_already_completed and not progress_already_exists: + # Create new SCORM progress + frappe.get_doc( + { + "doctype": "LMS Course Progress", + "lesson": lesson, + "status": "Complete" if scorm_details.is_complete else "Partially Complete", + "member": frappe.session.user, + "scorm_content": "" if scorm_details.is_complete else scorm_details.scorm_content, + } + ).save(ignore_permissions=True) + elif scorm_details and not lesson_already_completed and progress_already_exists: + # Update Existing SCORM Progress + frappe.db.set_value( + "LMS Course Progress", + progress_already_exists, + { + "lesson": lesson, + "status": "Complete" if scorm_details.is_complete else "Partially Complete", + "member": frappe.session.user, + "scorm_content": "" if scorm_details.is_complete else scorm_details.scorm_content, + }, + ) progress = get_course_progress(course) capture_progress_for_analytics(progress, course)