From 2631681c1d30c8ee95a31a24f9fc5cb227640f5b Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Thu, 18 Dec 2025 18:01:08 +0530 Subject: [PATCH 1/4] fix: enrollment in restricted courses by admin --- .../doctype/lms_enrollment/lms_enrollment.py | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/lms/lms/doctype/lms_enrollment/lms_enrollment.py b/lms/lms/doctype/lms_enrollment/lms_enrollment.py index f55c9ef0..e4c46360 100644 --- a/lms/lms/doctype/lms_enrollment/lms_enrollment.py +++ b/lms/lms/doctype/lms_enrollment/lms_enrollment.py @@ -8,7 +8,7 @@ from frappe.utils import ceil class LMSEnrollment(Document): - def validate(self): + def before_insert(self): self.validate_course_enrollment_eligibility() def on_update(self): @@ -22,7 +22,7 @@ class LMSEnrollment(Document): as_dict=True, ) - if course_details.disable_self_learning: + if course_details.disable_self_learning and not is_admin(): frappe.throw( _( "You cannot enroll in this course as self-learning is disabled. Please contact the Administrator." @@ -47,6 +47,15 @@ class LMSEnrollment(Document): frappe.throw(_("You need to complete the payment for this course before enrolling.")) +def is_admin(): + roles = frappe.get_roles(frappe.session.user) + admin_roles = ["Moderator", "Course Creator", "Batch Evaluator"] + for role in admin_roles: + if role in roles: + return True + return False + + def update_program_progress(member): programs = frappe.get_all("LMS Program Member", {"member": member}, ["parent", "name"]) @@ -77,14 +86,3 @@ def create_membership(course, batch=None, member=None, member_type="Student", ro ) enrollment.insert() return enrollment - - -@frappe.whitelist() -def update_current_membership(batch, course, member): - all_memberships = frappe.get_all("LMS Enrollment", {"member": member, "course": course}) - for membership in all_memberships: - frappe.db.set_value("LMS Enrollment", membership.name, "is_current", 0) - - current_membership = frappe.get_all("LMS Enrollment", {"batch_old": batch, "member": member}) - if len(current_membership): - frappe.db.set_value("LMS Enrollment", current_membership[0].name, "is_current", 1) From 09c668f7edf290107683a67be2c65e62f63a4b58 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Fri, 19 Dec 2025 16:21:22 +0530 Subject: [PATCH 2/4] fix: description on course details --- lms/lms/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lms/lms/utils.py b/lms/lms/utils.py index 055336ad..2bf2be7c 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -825,6 +825,7 @@ def get_course_fields(): "video_link", "card_gradient", "short_introduction", + "description", "published", "upcoming", "featured", From 01094cd10ae42988eb88f1f78621bec35bacf574 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Mon, 22 Dec 2025 10:55:36 +0530 Subject: [PATCH 3/4] fix: enrollment eligibility conditions --- lms/lms/doctype/lms_enrollment/lms_enrollment.py | 2 +- lms/lms/utils.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lms/lms/doctype/lms_enrollment/lms_enrollment.py b/lms/lms/doctype/lms_enrollment/lms_enrollment.py index e4c46360..11f6b292 100644 --- a/lms/lms/doctype/lms_enrollment/lms_enrollment.py +++ b/lms/lms/doctype/lms_enrollment/lms_enrollment.py @@ -39,7 +39,7 @@ class LMSEnrollment(Document): "reference_doctype": "LMS Course", "reference_docname": self.course, "member": self.member, - "payment_receipt": True, + "payment_received": True, }, ) diff --git a/lms/lms/utils.py b/lms/lms/utils.py index 2bf2be7c..3a737108 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -1800,7 +1800,7 @@ def validate_enrollment_eligibility(batch_doc, payment_doc=None): if not payment_doc or not payment_doc.payment_received: frappe.throw(_("Payment is required to enroll in this batch.")) - elif not batch_doc.allow_self_enrollment: + elif not batch_doc.allow_self_enrollment and not is_admin(): frappe.throw(_("Enrollment in this batch is restricted. Please contact the Administrator.")) students = frappe.db.count("LMS Batch Enrollment", {"batch": batch_doc.name}) @@ -1808,6 +1808,11 @@ def validate_enrollment_eligibility(batch_doc, payment_doc=None): frappe.throw(_("There are no seats available in this batch.")) +def is_admin(): + roles = frappe.get_roles(frappe.session.user) + return "Course Creator" in roles or "Moderator" in roles or "Batch Evaluator" in roles + + def create_enrollment(batch, payment_doc=None): new_student = frappe.new_doc("LMS Batch Enrollment") new_student.update( From d5e48f9502692698b78b206e7f8d7eb3c1b451b6 Mon Sep 17 00:00:00 2001 From: Jannat Patel Date: Tue, 23 Dec 2025 12:56:17 +0530 Subject: [PATCH 4/4] fix: batch enrollment conditions --- lms/lms/doctype/lms_batch/lms_batch.py | 11 ------- .../lms_batch_enrollment.py | 29 +++++++++++++++++++ .../lms_enrollment/lms_enrollment.json | 11 +++++-- .../doctype/lms_enrollment/lms_enrollment.py | 3 ++ lms/lms/utils.py | 25 ---------------- 5 files changed, 41 insertions(+), 38 deletions(-) diff --git a/lms/lms/doctype/lms_batch/lms_batch.py b/lms/lms/doctype/lms_batch/lms_batch.py index 61efdf80..c9f20215 100644 --- a/lms/lms/doctype/lms_batch/lms_batch.py +++ b/lms/lms/doctype/lms_batch/lms_batch.py @@ -30,7 +30,6 @@ class LMSBatch(Document): self.validate_payments_app() self.validate_amount_and_currency() self.validate_duplicate_assessments() - self.validate_membership() self.validate_timetable() self.validate_evaluation_end_date() @@ -82,16 +81,6 @@ class LMSBatch(Document): if self.evaluation_end_date and self.evaluation_end_date < self.end_date: frappe.throw(_("Evaluation end date cannot be less than the batch end date.")) - def validate_membership(self): - members = frappe.get_all("LMS Batch Enrollment", {"batch": self.name}, pluck="member") - for course in self.courses: - for member in members: - if not frappe.db.exists("LMS Enrollment", {"course": course.course, "member": member}): - enrollment = frappe.new_doc("LMS Enrollment") - enrollment.course = course.course - enrollment.member = member - enrollment.save() - def validate_seats_left(self): if cint(self.seat_count) < 0: frappe.throw(_("Seat count cannot be negative.")) diff --git a/lms/lms/doctype/lms_batch_enrollment/lms_batch_enrollment.py b/lms/lms/doctype/lms_batch_enrollment/lms_batch_enrollment.py index 63cd4d2a..25956117 100644 --- a/lms/lms/doctype/lms_batch_enrollment/lms_batch_enrollment.py +++ b/lms/lms/doctype/lms_batch_enrollment/lms_batch_enrollment.py @@ -17,6 +17,8 @@ class LMSBatchEnrollment(Document): def validate(self): self.validate_owner() self.validate_duplicate_members() + self.validate_payment() + self.validate_self_enrollment() self.validate_seat_availability() self.validate_course_enrollment() @@ -28,6 +30,32 @@ class LMSBatchEnrollment(Document): if "Moderator" not in roles and "Batch Evaluator" not in roles: frappe.throw(_("You must be a Moderator or Batch Evaluator to enroll users in a batch.")) + def validate_payment(self): + paid_batch = frappe.db.get_value("LMS Batch", self.batch, "paid_batch") + if paid_batch: + payment = frappe.db.exists( + "LMS Payment", + { + "payment_for_document_type": "LMS Batch", + "payment_for_document": self.batch, + "member": self.member, + "payment_received": True, + }, + ) + if not payment: + frappe.throw(_("Payment is required to enroll in this batch.")) + else: + self.payment = payment + + def validate_self_enrollment(self): + allow_self_enrollment = frappe.db.get_value("LMS Batch", self.batch, "allow_self_enrollment") + if not allow_self_enrollment and not self.is_admin(): + frappe.throw(_("Enrollment in this batch is restricted. Please contact the Administrator.")) + + def is_admin(self): + roles = frappe.get_roles(frappe.session.user) + return "Course Creator" in roles or "Moderator" in roles or "Batch Evaluator" in roles + def validate_duplicate_members(self): if frappe.db.exists( "LMS Batch Enrollment", @@ -52,6 +80,7 @@ class LMSBatchEnrollment(Document): enrollment = frappe.new_doc("LMS Enrollment") enrollment.course = course.course enrollment.member = self.member + enrollment.enrollment_from_batch = self.batch enrollment.save() def add_member_to_live_class(self): diff --git a/lms/lms/doctype/lms_enrollment/lms_enrollment.json b/lms/lms/doctype/lms_enrollment/lms_enrollment.json index 348e2437..838bb4d4 100644 --- a/lms/lms/doctype/lms_enrollment/lms_enrollment.json +++ b/lms/lms/doctype/lms_enrollment/lms_enrollment.json @@ -10,6 +10,7 @@ "progress", "payment", "current_lesson", + "enrollment_from_batch", "column_break_3", "member", "member_name", @@ -129,13 +130,19 @@ "fieldname": "member_image", "fieldtype": "Attach Image", "label": "Member Image" + }, + { + "fieldname": "enrollment_from_batch", + "fieldtype": "Link", + "label": "Enrollment from Batch", + "options": "LMS Batch" } ], "grid_page_length": 50, "index_web_pages_for_search": 1, "links": [], - "modified": "2025-12-15 21:27:30.733483", - "modified_by": "Administrator", + "modified": "2025-12-23 12:50:13.622277", + "modified_by": "sayali@frappe.io", "module": "LMS", "name": "LMS Enrollment", "owner": "Administrator", diff --git a/lms/lms/doctype/lms_enrollment/lms_enrollment.py b/lms/lms/doctype/lms_enrollment/lms_enrollment.py index 11f6b292..27046c4e 100644 --- a/lms/lms/doctype/lms_enrollment/lms_enrollment.py +++ b/lms/lms/doctype/lms_enrollment/lms_enrollment.py @@ -29,6 +29,9 @@ class LMSEnrollment(Document): ) ) + if self.enrollment_from_batch: + return + if not course_details.published: frappe.throw(_("You cannot enroll in an unpublished course.")) diff --git a/lms/lms/utils.py b/lms/lms/utils.py index 3a737108..e8399459 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -1775,11 +1775,7 @@ def enroll_in_batch(batch, payment_name=None): if not frappe.db.exists("LMS Batch", batch): frappe.throw(_("The specified batch does not exist.")) - batch_doc = frappe.db.get_value( - "LMS Batch", batch, ["name", "seat_count", "allow_self_enrollment", "paid_batch"], as_dict=True - ) payment_doc = get_payment_details(payment_name) - validate_enrollment_eligibility(batch_doc, payment_doc) create_enrollment(batch, payment_doc) @@ -1792,27 +1788,6 @@ def get_payment_details(payment_name): return payment_doc -def validate_enrollment_eligibility(batch_doc, payment_doc=None): - if frappe.db.exists("LMS Batch Enrollment", {"batch": batch_doc.name, "member": frappe.session.user}): - frappe.throw(_("You are already enrolled in this batch.")) - - if batch_doc.paid_batch: - if not payment_doc or not payment_doc.payment_received: - frappe.throw(_("Payment is required to enroll in this batch.")) - - elif not batch_doc.allow_self_enrollment and not is_admin(): - frappe.throw(_("Enrollment in this batch is restricted. Please contact the Administrator.")) - - students = frappe.db.count("LMS Batch Enrollment", {"batch": batch_doc.name}) - if batch_doc.seat_count and students >= batch_doc.seat_count: - frappe.throw(_("There are no seats available in this batch.")) - - -def is_admin(): - roles = frappe.get_roles(frappe.session.user) - return "Course Creator" in roles or "Moderator" in roles or "Batch Evaluator" in roles - - def create_enrollment(batch, payment_doc=None): new_student = frappe.new_doc("LMS Batch Enrollment") new_student.update(