feat: class billing
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{% extends "lms/templates/lms_base.html" %}
|
||||
{% block title %}
|
||||
{{ course.title if course.title else _("New Course") }}
|
||||
{{ title }} {{ _("Billing") }}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<div class="common-page-style">
|
||||
<div class="container form-width common-card-style column-card px-0 h-0 mt-8">
|
||||
{{ Header() }}
|
||||
{{ CourseDetails() }}
|
||||
{{ Details() }}
|
||||
{{ BillingDetails() }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -20,23 +20,24 @@
|
||||
{{ _("Order Details") }}
|
||||
</div>
|
||||
<div>
|
||||
{{ _("Enter the billing information and complete the payment to purchase this course.") }}
|
||||
{{ _("Enter the billing information and complete the payment to purchase this {0}.").format(module) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro CourseDetails() %}
|
||||
{% macro Details() %}
|
||||
<div class="px-4 pt-5 border-top">
|
||||
<div class="">
|
||||
<div class="flex mb-2">
|
||||
<div class="field-label">
|
||||
{{ _("Course Name: ") }} {{ course.title }}
|
||||
{% set label = "Course Name" if module == "course" else "Class Name" %}
|
||||
{{ _(label) }} : {{ title }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex">
|
||||
<div class="field-label">
|
||||
{{ _("Total Price: ") }} {{ frappe.utils.fmt_money(course.course_price, 2, course.currency) }}
|
||||
{{ _("Total Price: ") }} {{ frappe.utils.fmt_money(amount, 2, currency) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -49,7 +50,7 @@
|
||||
{{ _("Billing Details") }}
|
||||
</div>
|
||||
<div id="billing-form"></div>
|
||||
<button class="btn btn-primary btn-md btn-pay" data-course="{{ course.name | urlencode }}">
|
||||
<button class="btn btn-primary btn-md btn-pay" data-doctype="{{ doctype }}" data-name="{{ docname | urlencode }}">
|
||||
{{ "Proceed to Payment" }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
frappe.ready(() => {
|
||||
if ($("#billing-form").length) {
|
||||
setup_billing();
|
||||
frappe.require("controls.bundle.js", () => {
|
||||
setup_billing();
|
||||
});
|
||||
}
|
||||
|
||||
$(".btn-pay").click((e) => {
|
||||
@@ -66,19 +68,22 @@ const setup_billing = () => {
|
||||
|
||||
const generate_payment_link = (e) => {
|
||||
address = this.billing.get_values();
|
||||
let course = decodeURIComponent($(e.currentTarget).attr("data-course"));
|
||||
let doctype = $(e.currentTarget).attr("data-doctype");
|
||||
let docname = decodeURIComponent($(e.currentTarget).attr("data-name"));
|
||||
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.lms_course.lms_course.get_payment_options",
|
||||
method: "lms.lms.utils.get_payment_options",
|
||||
args: {
|
||||
course: course,
|
||||
doctype: doctype,
|
||||
docname: docname,
|
||||
phone: address.phone,
|
||||
},
|
||||
callback: (data) => {
|
||||
data.message.handler = (response) => {
|
||||
handle_success(
|
||||
response,
|
||||
course,
|
||||
doctype,
|
||||
docname,
|
||||
address,
|
||||
data.message.order_id
|
||||
);
|
||||
@@ -89,12 +94,13 @@ const generate_payment_link = (e) => {
|
||||
});
|
||||
};
|
||||
|
||||
const handle_success = (response, course, address, order_id) => {
|
||||
const handle_success = (response, doctype, docname, address, order_id) => {
|
||||
frappe.call({
|
||||
method: "lms.lms.doctype.lms_course.lms_course.verify_payment",
|
||||
method: "lms.lms.utils.verify_payment",
|
||||
args: {
|
||||
response: response,
|
||||
course: course,
|
||||
doctype: doctype,
|
||||
docname: docname,
|
||||
address: address,
|
||||
order_id: order_id,
|
||||
},
|
||||
|
||||
@@ -3,21 +3,66 @@ from frappe import _
|
||||
|
||||
|
||||
def get_context(context):
|
||||
course_name = frappe.form_dict.course
|
||||
|
||||
if not course_name:
|
||||
raise ValueError(_("Course is required."))
|
||||
module = frappe.form_dict.module
|
||||
docname = frappe.form_dict.modulename
|
||||
|
||||
if frappe.session.user == "Guest":
|
||||
raise frappe.PermissionError(_("You are not allowed to access this page."))
|
||||
|
||||
membership = frappe.db.exists(
|
||||
"LMS Batch Membership", {"member": frappe.session.user, "course": course_name}
|
||||
)
|
||||
if module not in ["course", "class"]:
|
||||
raise ValueError(_("Module is incorrect."))
|
||||
|
||||
if membership:
|
||||
raise frappe.PermissionError(_("You are already enrolled for this course"))
|
||||
doctype = "LMS Course" if module == "course" else "LMS Class"
|
||||
context.module = module
|
||||
context.docname = docname
|
||||
context.doctype = doctype
|
||||
|
||||
context.course = frappe.db.get_value(
|
||||
"LMS Course", course_name, ["title", "name", "course_price", "currency"], as_dict=True
|
||||
)
|
||||
if not frappe.db.exists(doctype, docname):
|
||||
print(doctype, docname)
|
||||
raise ValueError(_("Module Name is incorrect or does not exist."))
|
||||
|
||||
if doctype == "LMS Course":
|
||||
membership = frappe.db.exists(
|
||||
"LMS Batch Membership", {"member": frappe.session.user, "course": docname}
|
||||
)
|
||||
if membership:
|
||||
raise frappe.PermissionError(_("You are already enrolled for this course"))
|
||||
|
||||
else:
|
||||
membership = frappe.db.exists(
|
||||
"Class Student", {"student": frappe.session.user, "parent": docname}
|
||||
)
|
||||
if membership:
|
||||
raise frappe.PermissionError(_("You are already enrolled for this class"))
|
||||
|
||||
if doctype == "LMS Course":
|
||||
course = frappe.db.get_value(
|
||||
"LMS Course",
|
||||
docname,
|
||||
["title", "name", "paid_course", "course_price", "currency"],
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
if not course.paid_course:
|
||||
raise frappe.PermissionError(_("This course is free."))
|
||||
|
||||
context.title = course.title
|
||||
context.amount = course.course_price
|
||||
context.currency = course.currency
|
||||
|
||||
else:
|
||||
class_info = frappe.db.get_value(
|
||||
"LMS Class",
|
||||
docname,
|
||||
["title", "name", "paid_class", "amount", "currency"],
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
if not class_info.paid_class:
|
||||
raise frappe.PermissionError(
|
||||
_("To join this class, please contact the Administrator.")
|
||||
)
|
||||
|
||||
context.title = class_info.title
|
||||
context.amount = class_info.amount
|
||||
context.currency = class_info.currency
|
||||
|
||||
@@ -85,12 +85,6 @@
|
||||
{% macro ClassSections(class_info, class_courses, class_students, flow) %}
|
||||
<div class="mt-4">
|
||||
|
||||
{% if is_moderator %}
|
||||
<button class="btn btn-default btn-sm pull-right" id="create-class">
|
||||
{{ _("Edit") }}
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
<ul class="nav lms-nav" id="classes-tab">
|
||||
|
||||
{% if is_student %}
|
||||
@@ -610,17 +604,16 @@
|
||||
<script>
|
||||
frappe.boot.user = {
|
||||
"can_create": [],
|
||||
"can_select": ["User", "LMS Category", "LMS Assignment", "LMS Quiz"],
|
||||
"can_read": ["User", "LMS Category", "LMS Assignment", "LMS Quiz"]
|
||||
"can_select": ["User", "LMS Assignment", "LMS Quiz"],
|
||||
"can_read": ["User", "LMS Assignment", "LMS Quiz"]
|
||||
};
|
||||
|
||||
frappe.boot.single_types = []
|
||||
|
||||
let class_info = {{ class_info | json }};
|
||||
</script>
|
||||
{% else %}
|
||||
<script>
|
||||
frappe.boot.user = {
|
||||
frappe.boot.user= {
|
||||
"can_create": [],
|
||||
"can_select": ["LMS Course"],
|
||||
"can_read": ["LMS Course"]
|
||||
@@ -629,5 +622,4 @@
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
{{ include_script('controls.bundle.js') }}
|
||||
{% endblock %}
|
||||
@@ -1,6 +1,11 @@
|
||||
frappe.ready(() => {
|
||||
let self = this;
|
||||
|
||||
if ($("#live-class-form").length) {
|
||||
frappe.require("controls.bundle.js", () => {
|
||||
make_live_class_form();
|
||||
});
|
||||
}
|
||||
$(".btn-add-student").click((e) => {
|
||||
show_student_modal(e);
|
||||
});
|
||||
@@ -9,10 +14,6 @@ frappe.ready(() => {
|
||||
remove_student(e);
|
||||
});
|
||||
|
||||
if ($("#live-class-form").length) {
|
||||
make_live_class_form();
|
||||
}
|
||||
|
||||
$("#open-class-modal").click((e) => {
|
||||
e.preventDefault();
|
||||
$("#live-class-modal").modal("show");
|
||||
@@ -25,7 +26,6 @@ frappe.ready(() => {
|
||||
$(".btn-add-course").click((e) => {
|
||||
show_course_modal(e);
|
||||
});
|
||||
|
||||
$(".btn-remove-course").click((e) => {
|
||||
remove_course(e);
|
||||
});
|
||||
@@ -309,6 +309,12 @@ const show_course_modal = () => {
|
||||
fieldname: "course",
|
||||
reqd: 1,
|
||||
},
|
||||
{
|
||||
fieldtype: "Link",
|
||||
options: "Course Evaluator",
|
||||
label: __("Course Evaluator"),
|
||||
fieldname: "evaluator",
|
||||
},
|
||||
],
|
||||
primary_action_label: __("Add"),
|
||||
primary_action(values) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from frappe import _
|
||||
import frappe
|
||||
from frappe.utils import getdate, cint
|
||||
from lms.www.utils import get_assessments
|
||||
from lms.www.utils import get_assessments, is_student
|
||||
from lms.lms.utils import (
|
||||
has_course_moderator_role,
|
||||
has_course_evaluator_role,
|
||||
@@ -36,6 +36,10 @@ def get_context(context):
|
||||
"start_time",
|
||||
"end_time",
|
||||
"category",
|
||||
"paid_class",
|
||||
"amount",
|
||||
"currency",
|
||||
"prerequisite",
|
||||
],
|
||||
as_dict=True,
|
||||
)
|
||||
@@ -67,7 +71,7 @@ def get_context(context):
|
||||
context.class_students = get_class_student_details(
|
||||
class_students, class_courses, context.assessments
|
||||
)
|
||||
context.is_student = is_student(class_students)
|
||||
context.is_student = is_student(class_name)
|
||||
|
||||
if not context.is_student and not context.is_moderator and not context.is_evaluator:
|
||||
raise frappe.PermissionError(_("You don't have permission to access this page."))
|
||||
@@ -205,11 +209,6 @@ def sort_students(class_students):
|
||||
return class_students
|
||||
|
||||
|
||||
def is_student(class_students):
|
||||
students = [student.student for student in class_students]
|
||||
return frappe.session.user in students
|
||||
|
||||
|
||||
def get_scheduled_flow(class_name):
|
||||
chapters = []
|
||||
|
||||
|
||||
214
lms/www/classes/class_details.html
Normal file
214
lms/www/classes/class_details.html
Normal file
@@ -0,0 +1,214 @@
|
||||
{% extends "lms/templates/lms_base.html" %}
|
||||
{% block title %}
|
||||
{{ _(class_info.title) }}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block page_content %}
|
||||
<div class="common-page-style lms-page-style">
|
||||
{{ ClassHeader(class_info) }}
|
||||
<div class="container">
|
||||
{{ CourseHeaderOverlay(class_info) }}
|
||||
<div class="pt-10">
|
||||
{{ Prerequisites(class_info) }}
|
||||
{{ CourseList(class_info) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% macro ClassHeader(class_info) %}
|
||||
<div class="course-head-container">
|
||||
<div class="container">
|
||||
<div class="course-card-wide">
|
||||
{{ BreadCrumb(class_info) }}
|
||||
{{ ClassHeaderDetails(class_info) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro BreadCrumb(class_info) %}
|
||||
<article class="mb-8">
|
||||
<a class="dark-links" href="/classes">
|
||||
{{ _("All Classes") }}
|
||||
</a>
|
||||
<img class="" src="/assets/lms/icons/chevron-right.svg">
|
||||
<span class="breadcrumb-destination">
|
||||
{{ _("Class Details") }}
|
||||
</span>
|
||||
</article>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro ClassHeaderDetails(class_info) %}
|
||||
<div class="class-details" data-class="{{ class_info.name }}">
|
||||
<div class="flex align-center">
|
||||
<span>
|
||||
{{ class_info.courses | length }} {{ _("Courses") }}
|
||||
</span>
|
||||
<span class="px-2"> · </span>
|
||||
<span>
|
||||
{{ class_info.students | length }} {{ _("Students") }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="page-title">
|
||||
{{ class_info.title }}
|
||||
</div>
|
||||
|
||||
<div class="">
|
||||
{{ class_info.description }}
|
||||
</div>
|
||||
|
||||
<div class="mt-8">
|
||||
<svg class="icon icon-sm">
|
||||
<use href="#icon-calendar"></use>
|
||||
</svg>
|
||||
<span>
|
||||
{{ frappe.utils.format_date(class_info.start_date, "long") }} -
|
||||
</span>
|
||||
<span>
|
||||
{{ frappe.utils.format_date(class_info.end_date, "long") }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{% if class_info.start_time and class_info.end_time %}
|
||||
<div class="mt-1">
|
||||
<svg class="icon icon-sm">
|
||||
<use href="#icon-clock"></use>
|
||||
</svg>
|
||||
<span>
|
||||
{{ frappe.utils.format_time(class_info.start_time, "hh:mm a") }} -
|
||||
</span>
|
||||
<span>
|
||||
{{ frappe.utils.format_time(class_info.end_time, "hh:mm a") }}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro CourseHeaderOverlay(class_info) %}
|
||||
<div class="course-overlay-card class-overlay">
|
||||
|
||||
<div class="course-overlay-content">
|
||||
{% if class_info.paid_class %}
|
||||
<div class="bold-heading">
|
||||
{{ frappe.utils.fmt_money(class_info.amount, 0, class_info.currency) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="vertically-center mt-2">
|
||||
<svg class="icon icon-md mr-1">
|
||||
<use href="#icon-education"></use>
|
||||
</svg>
|
||||
{{ class_info.courses | length }} {{ _("Courses") }}
|
||||
</div>
|
||||
|
||||
<div class="vertically-center mt-2">
|
||||
<svg class="icon icon-md mr-1">
|
||||
<use class="" href="#icon-users">
|
||||
</svg>
|
||||
{{ class_info.students | length }} {{ _("Students") }}
|
||||
</div>
|
||||
|
||||
<div class="mt-2">
|
||||
<svg class="icon icon-sm">
|
||||
<use href="#icon-calendar"></use>
|
||||
</svg>
|
||||
<span>
|
||||
{{ frappe.utils.format_date(class_info.start_date, "long") }} -
|
||||
</span>
|
||||
<span>
|
||||
{{ frappe.utils.format_date(class_info.end_date, "long") }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{% if class_info.start_time and class_info.end_time %}
|
||||
<div class="mt-2">
|
||||
<svg class="icon icon-sm">
|
||||
<use href="#icon-clock"></use>
|
||||
</svg>
|
||||
<span>
|
||||
{{ frappe.utils.format_time(class_info.start_time, "hh:mm a") }} -
|
||||
</span>
|
||||
<span>
|
||||
{{ frappe.utils.format_time(class_info.end_time, "hh:mm a") }}
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="mt-2">
|
||||
{% if is_moderator or is_evaluator or is_student %}
|
||||
<a class="btn btn-primary wide-button" href="/classes/{{ class_info.name }}">
|
||||
{{ _("Checkout Class") }}
|
||||
</a>
|
||||
{% elif class_info.paid_class %}
|
||||
<a class="btn btn-primary wide-button" href="/billing/class/{{ class_info.name }}">
|
||||
{{ _("Register Now") }}
|
||||
</a>
|
||||
{% else %}
|
||||
<div class="alert alert-info">
|
||||
{{ _("To join this class, please contact the Administrator.") }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if is_moderator %}
|
||||
<div class="mt-2">
|
||||
<div class="btn btn-secondary wide-button" id="create-class">
|
||||
{{ _("Edit Class") }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro Prerequisites(class_info) %}
|
||||
<div class="course-description-section w-50">
|
||||
<div class="page-title">
|
||||
{{ _("Prerequisite Knowledge") }}
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
{{ class_info.prerequisite }}
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro CourseList(class_info) %}
|
||||
<div>
|
||||
<div class="page-title">
|
||||
{{ _("Courses") }}
|
||||
</div>
|
||||
{% if class_info.courses | length %}
|
||||
<div class="cards-parent mt-2">
|
||||
{% for course in class_info.courses %}
|
||||
<div class="h-100">
|
||||
{{ widgets.CourseCard(course=course, read_only=False) }}
|
||||
<button class="btn icon-btn btn-default btn-block btn-remove-course" data-course="{{ course.name }}">
|
||||
<svg class="icon icon-sm">
|
||||
<use href="#icon-delete"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="">
|
||||
{{ _("No courses") }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{%- block script %}
|
||||
{{ super() }}
|
||||
{% if is_moderator %}
|
||||
<script>
|
||||
let class_info = {{ class_info | json }};
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
3
lms/www/classes/class_details.js
Normal file
3
lms/www/classes/class_details.js
Normal file
@@ -0,0 +1,3 @@
|
||||
frappe.ready(() => {
|
||||
frappe.require("controls.bundle.js");
|
||||
});
|
||||
21
lms/www/classes/class_details.py
Normal file
21
lms/www/classes/class_details.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import frappe
|
||||
from lms.lms.utils import has_course_moderator_role, has_course_evaluator_role
|
||||
from lms.www.utils import is_student
|
||||
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
class_name = frappe.form_dict["classname"]
|
||||
|
||||
context.class_info = frappe.get_doc("LMS Class", class_name)
|
||||
|
||||
for course in context.class_info.courses:
|
||||
course.update(
|
||||
frappe.db.get_value(
|
||||
"LMS Course", course.course, ["name", "short_introduction", "image"], as_dict=1
|
||||
)
|
||||
)
|
||||
|
||||
context.is_moderator = has_course_moderator_role()
|
||||
context.is_evaluator = has_course_evaluator_role()
|
||||
context.is_student = is_student(class_name)
|
||||
@@ -43,7 +43,7 @@
|
||||
{% if is_moderator %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="tab" href="#past">
|
||||
{{ _("Past Classes") }}
|
||||
{{ _("Archived") }}
|
||||
<span class="course-list-count">
|
||||
{{ past_classes | length }}
|
||||
</span>
|
||||
@@ -54,7 +54,7 @@
|
||||
{% if frappe.session.user != "Guest" %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="tab" href="#my-class">
|
||||
{{ _("My Classes") }}
|
||||
{{ _("Enrolled") }}
|
||||
<span class="course-list-count">
|
||||
{{ my_classes | length }}
|
||||
</span>
|
||||
@@ -68,18 +68,18 @@
|
||||
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="upcoming" role="tabpanel" aria-labelledby="upcoming">
|
||||
{{ ClassCards(upcoming_classes) }}
|
||||
{{ ClassCards(upcoming_classes, show_price=True) }}
|
||||
</div>
|
||||
|
||||
{% if is_moderator %}
|
||||
<div class="tab-pane" id="past" role="tabpanel" aria-labelledby="past">
|
||||
{{ ClassCards(past_classes) }}
|
||||
{{ ClassCards(past_classes, show_price=False) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if frappe.session.user != "Guest" %}
|
||||
<div class="tab-pane" id="my-class" role="tabpanel" aria-labelledby="my-classes">
|
||||
{{ ClassCards(my_classes) }}
|
||||
{{ ClassCards(my_classes, show_price=False) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
</article>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro ClassCards(classes) %}
|
||||
{% macro ClassCards(classes, show_price=False) %}
|
||||
<div class="lms-card-parent">
|
||||
{% for class in classes %}
|
||||
{% set course_count = frappe.db.count("Class Course", {"parent": class.name}) %}
|
||||
@@ -105,6 +105,12 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if show_price and class.paid_class %}
|
||||
<div class="bold-heading">
|
||||
{{ frappe.utils.fmt_money(class.amount, 0, class.currency) }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="mt-auto mb-1">
|
||||
<svg class="icon icon-sm">
|
||||
<use href="#icon-calendar"></use>
|
||||
@@ -131,7 +137,11 @@
|
||||
{{ student_count }} {{ _("Students") }}
|
||||
</div>
|
||||
|
||||
<a class="stretched-link" href="/classes/{{ class.name }}"></a>
|
||||
{% if is_student(class.name) %}
|
||||
<a class="stretched-link" href="/classes/{{ class.name }}"></a>
|
||||
{% else %}
|
||||
<a class="stretched-link" href="/classes/details/{{ class.name }}"></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import frappe
|
||||
from frappe.utils import getdate
|
||||
from lms.lms.utils import has_course_moderator_role
|
||||
from lms.lms.utils import has_course_moderator_role, has_course_evaluator_role
|
||||
|
||||
|
||||
def get_context(context):
|
||||
context.no_cache = 1
|
||||
context.is_moderator = has_course_moderator_role()
|
||||
context.is_evaluator = has_course_evaluator_role()
|
||||
classes = frappe.get_all(
|
||||
"LMS Class",
|
||||
fields=[
|
||||
@@ -15,6 +16,8 @@ def get_context(context):
|
||||
"start_date",
|
||||
"end_date",
|
||||
"paid_class",
|
||||
"amount",
|
||||
"currency",
|
||||
"seat_count",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
{{ CourseHomeHeader(course) }}
|
||||
<div class="course-home-page">
|
||||
<div class="container">
|
||||
{{ CourseHeaderOverlay(course) }}
|
||||
<div class="course-body-container">
|
||||
{{ CourseHeaderOverlay(course) }}
|
||||
{{ Description(course) }}
|
||||
{{ widgets.CourseOutline(course=course, membership=membership, is_user_interested=is_user_interested) }}
|
||||
{% if course.status == "Approved" and not frappe.utils.cint(course.upcoming) %}
|
||||
@@ -41,7 +41,7 @@
|
||||
{% macro BreadCrumb(course) %}
|
||||
<div class="breadcrumb">
|
||||
<a class="dark-links" href="/courses">{{ _("All Courses") }}</a>
|
||||
<img class="ml-1 mr-1" src="/assets/lms/icons/chevron-right.svg">
|
||||
<img class="" src="/assets/lms/icons/chevron-right.svg">
|
||||
<span class="breadcrumb-destination">{{ course.title if course.title else _("New Course") }}</span>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
@@ -57,8 +57,8 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div id="title" {% if course.name %} data-course="{{ course.name | urlencode }}" {% endif %} class="page-title">
|
||||
{% if course.title %} {{ course.title }} {% endif %}
|
||||
<div id="title" class="page-title">
|
||||
{{ course.title }}
|
||||
</div>
|
||||
|
||||
<div id="intro">
|
||||
@@ -228,7 +228,7 @@
|
||||
</a>
|
||||
|
||||
{% elif course.paid_course and not is_instructor %}
|
||||
<a class="btn btn-primary wide-button" href="/billing/{{ course.name | urlencode }}">
|
||||
<a class="btn btn-primary wide-button" href="/billing/course/{{ course.name | urlencode }}">
|
||||
{{ _("Buy This Course") }}
|
||||
</a>
|
||||
|
||||
|
||||
@@ -128,3 +128,16 @@ def get_quiz_details(assessment, member):
|
||||
existing_submission[0].name if len(existing_submission) else "new-submission"
|
||||
)
|
||||
assessment.url = f"/quiz-submission/{assessment.assessment_name}/{submission_name}"
|
||||
|
||||
|
||||
def is_student(class_name, member=None):
|
||||
if not member:
|
||||
member = frappe.session.user
|
||||
|
||||
return frappe.db.exists(
|
||||
"Class Student",
|
||||
{
|
||||
"student": member,
|
||||
"parent": class_name,
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user