diff --git a/lms/lms/doctype/lms_batch/lms_batch.js b/lms/lms/doctype/lms_batch/lms_batch.js index 3028e564..07e88ed3 100644 --- a/lms/lms/doctype/lms_batch/lms_batch.js +++ b/lms/lms/doctype/lms_batch/lms_batch.js @@ -12,7 +12,12 @@ frappe.ui.form.on("LMS Batch", { }); frm.set_query("reference_doctype", "timetable", function () { - let doctypes = ["Course Lesson", "LMS Quiz", "LMS Assignment"]; + let doctypes = [ + "Course Lesson", + "LMS Quiz", + "LMS Assignment", + "LMS Live Class", + ]; return { filters: { name: ["in", doctypes], diff --git a/lms/lms/doctype/lms_batch/lms_batch.json b/lms/lms/doctype/lms_batch/lms_batch.json index 2f916303..d4e4ea6d 100644 --- a/lms/lms/doctype/lms_batch/lms_batch.json +++ b/lms/lms/doctype/lms_batch/lms_batch.json @@ -146,8 +146,9 @@ }, { "fieldname": "category", - "fieldtype": "Autocomplete", - "label": "Category" + "fieldtype": "Link", + "label": "Category", + "options": "LMS Category" }, { "fieldname": "section_break_ubxi", @@ -221,7 +222,7 @@ ], "index_web_pages_for_search": 1, "links": [], - "modified": "2023-09-20 11:25:10.683688", + "modified": "2023-09-20 14:40:45.940540", "modified_by": "Administrator", "module": "LMS", "name": "LMS Batch", diff --git a/lms/lms/utils.py b/lms/lms/utils.py index 9abeb5f1..f66db678 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -18,6 +18,7 @@ from frappe.utils import ( get_datetime, getdate, validate_phone_number, + ceil, ) from frappe.utils.dateutils import get_period from lms.lms.md import find_macros, markdown_to_html @@ -844,7 +845,7 @@ def get_payment_options(doctype, docname, phone, country): validate_phone_number(phone, True) details = get_details(doctype, docname) details.amount, details.currency = check_multicurrency( - details.amount, details.currency + details.amount, details.currency, country ) if details.currency == "INR": details.amount, details.gst_applied = apply_gst(details.amount, country) @@ -868,18 +869,20 @@ def get_payment_options(doctype, docname, phone, country): return options -def check_multicurrency(amount, currency): +def check_multicurrency(amount, currency, country=None): show_usd_equivalent = frappe.db.get_single_value("LMS Settings", "show_usd_equivalent") exception_country = frappe.get_all( "Payment Country", filters={"parent": "LMS Settings"}, pluck="country" ) apply_rounding = frappe.db.get_single_value("LMS Settings", "apply_rounding") - country = frappe.db.get_value("User", frappe.session.user, "country") + country = country or frappe.db.get_value( + "Address", {"email_id": frappe.session.user}, "country" + ) if not show_usd_equivalent or currency == "USD": return amount, currency - if exception_country and country in exception_country: + if not country or (exception_country and country in exception_country): return amount, currency exchange_rate = get_current_exchange_rate(currency, "USD") @@ -887,7 +890,7 @@ def check_multicurrency(amount, currency): currency = "USD" if apply_rounding and amount % 100 != 0: - amount = amount + 100 - amount % 100 + amount = ceil(amount + 100 - amount % 100) return amount, currency @@ -930,7 +933,15 @@ def get_details(doctype, docname): def save_address(address): - address.update( + filters = {"email_id": frappe.session.user} + exists = frappe.db.exists("Address", filters) + if exists: + address_doc = frappe.get_last_doc("Address", filters=filters) + else: + address_doc = frappe.new_doc("Address") + + address_doc.update(address) + address_doc.update( { "address_title": frappe.db.get_value("User", frappe.session.user, "full_name"), "address_type": "Billing", @@ -938,10 +949,8 @@ def save_address(address): "email_id": frappe.session.user, } ) - doc = frappe.new_doc("Address") - doc.update(address) - doc.save(ignore_permissions=True) - return doc.name + address_doc.save(ignore_permissions=True) + return address_doc.name def get_client(): @@ -1064,3 +1073,10 @@ def get_current_exchange_rate(source, target="USD"): response = requests.request("GET", url) details = response.json() return details["rates"][target] + + +@frappe.whitelist() +def change_currency(amount, currency, country=None): + amount = cint(amount) + amount, currency = check_multicurrency(amount, currency, country) + return fmt_money(amount, 0, currency) diff --git a/lms/public/css/style.css b/lms/public/css/style.css index e79eec3b..a6ea778b 100644 --- a/lms/public/css/style.css +++ b/lms/public/css/style.css @@ -2442,4 +2442,15 @@ select { justify-content: space-between; width: 50%; margin: 0 auto 1rem; +} + +.batch-details { + width: 50%; + margin: 2rem 0; +} + +@media (max-width: 1000px) { + .batch-details { + width: 100%; + } } \ No newline at end of file diff --git a/lms/public/js/common_functions.js b/lms/public/js/common_functions.js index 8da2d052..59edd021 100644 --- a/lms/public/js/common_functions.js +++ b/lms/public/js/common_functions.js @@ -320,6 +320,7 @@ const open_batch_dialog = () => { label: __("Category"), fieldname: "category", options: "LMS Category", + only_select: 1, default: batch_info && batch_info.category, }, { diff --git a/lms/www/batches/batch.py b/lms/www/batches/batch.py index 00aac227..15d1b9d4 100644 --- a/lms/www/batches/batch.py +++ b/lms/www/batches/batch.py @@ -1,6 +1,6 @@ from frappe import _ import frappe -from frappe.utils import getdate, get_datetime +from frappe.utils import getdate from lms.www.utils import get_assessments, is_student from lms.lms.utils import ( has_course_moderator_role, @@ -52,14 +52,14 @@ def get_context(context): "Batch Course", {"parent": batch_name}, ["name", "course", "title"], - order_by="creation desc", + order_by="idx", ) batch_students = frappe.get_all( "Batch Student", {"parent": batch_name}, ["name", "student", "student_name", "username"], - order_by="creation desc", + order_by="idx", ) context.batch_courses = get_class_course_details(batch_courses) diff --git a/lms/www/batches/batch_details.html b/lms/www/batches/batch_details.html index b1967306..8d1d9ee9 100644 --- a/lms/www/batches/batch_details.html +++ b/lms/www/batches/batch_details.html @@ -164,24 +164,26 @@ {% macro BatchDetails(batch_info) %} -
-
- {{ batch_info.batch_details }} -
+
+ {{ batch_info.batch_details }}
{% endmacro %} {% macro CourseList(courses) %}
- {% if is_moderator %} - - {% endif %} -
- {{ _("Courses") }} + +
+
+ {{ _("Courses") }} +
+ {% if is_moderator %} + + {% endif %}
+ {% if courses | length %}
{% for course in courses %} diff --git a/lms/www/batches/batch_details.py b/lms/www/batches/batch_details.py index 91d11927..df044a1e 100644 --- a/lms/www/batches/batch_details.py +++ b/lms/www/batches/batch_details.py @@ -1,6 +1,10 @@ import frappe from frappe import _ -from lms.lms.utils import has_course_moderator_role, has_course_evaluator_role +from lms.lms.utils import ( + has_course_moderator_role, + has_course_evaluator_role, + check_multicurrency, +) from lms.www.utils import is_student @@ -29,6 +33,13 @@ def get_context(context): as_dict=1, ) + if context.batch_info.amount and context.batch_info.currency: + amount, currency = check_multicurrency( + context.batch_info.amount, context.batch_info.currency + ) + context.batch_info.amount = amount + context.batch_info.currency = currency + context.is_moderator = has_course_moderator_role() context.is_evaluator = has_course_evaluator_role() context.is_student = is_student(batch_name) @@ -44,7 +55,7 @@ def get_context(context): "Batch Course", {"parent": batch_name}, ["name as batch_course", "course", "title", "evaluator"], - order_by="creation desc", + order_by="idx", ) for course in context.courses: diff --git a/lms/www/batches/index.py b/lms/www/batches/index.py index 273af9d2..292d7cab 100644 --- a/lms/www/batches/index.py +++ b/lms/www/batches/index.py @@ -1,6 +1,10 @@ import frappe from frappe.utils import getdate -from lms.lms.utils import has_course_moderator_role, has_course_evaluator_role +from lms.lms.utils import ( + has_course_moderator_role, + has_course_evaluator_role, + check_multicurrency, +) def get_context(context): @@ -28,6 +32,12 @@ def get_context(context): for batch in batches: batch.student_count = frappe.db.count("Batch Student", {"parent": batch.name}) batch.course_count = frappe.db.count("Batch Course", {"parent": batch.name}) + + if batch.amount and batch.currency: + amount, currency = check_multicurrency(batch.amount, batch.currency) + batch.amount = amount + batch.currency = currency + batch.seats_left = ( batch.seat_count - batch.student_count if batch.seat_count else None ) diff --git a/lms/www/billing/billing.html b/lms/www/billing/billing.html index d9c5a956..bf1c1213 100644 --- a/lms/www/billing/billing.html +++ b/lms/www/billing/billing.html @@ -37,7 +37,8 @@
- {{ _("Total Price: ") }} {{ frappe.utils.fmt_money(amount, 2, currency) }} + {{ _("Total Price: ") }} + {{ frappe.utils.fmt_money(amount, 2, currency) }}
{% if gst_applied %} @@ -64,4 +65,11 @@ {%- block script %} {{ super() }} + {% endblock %} diff --git a/lms/www/billing/billing.js b/lms/www/billing/billing.js index 1bb2e24f..5a5bc8a2 100644 --- a/lms/www/billing/billing.js +++ b/lms/www/billing/billing.js @@ -18,23 +18,27 @@ const setup_billing = () => { label: __("Billing Name"), fieldname: "billing_name", reqd: 1, + default: address && address.billing_name, }, { fieldtype: "Data", label: __("Address Line 1"), fieldname: "address_line1", reqd: 1, + default: address && address.address_line1, }, { fieldtype: "Data", label: __("Address Line 2"), fieldname: "address_line2", + default: address && address.address_line2, }, { fieldtype: "Data", label: __("City/Town"), fieldname: "city", reqd: 1, + default: address && address.city, }, { fieldtype: "Column Break", @@ -43,6 +47,7 @@ const setup_billing = () => { fieldtype: "Data", label: __("State/Province"), fieldname: "state", + default: address && address.state, }, { fieldtype: "Link", @@ -51,18 +56,24 @@ const setup_billing = () => { options: "Country", reqd: 1, only_select: 1, + default: address && address.country, + change: () => { + change_currency(); + }, }, { fieldtype: "Data", label: __("Postal Code"), fieldname: "pincode", reqd: 1, + default: address && address.pincode, }, { fieldtype: "Data", label: __("Phone Number"), fieldname: "phone", reqd: 1, + default: address && address.phone, }, { fieldtype: "Section Break", @@ -143,3 +154,33 @@ const handle_success = (response, doctype, docname, address, order_id) => { }, }); }; + +const change_currency = () => { + let country = this.billing.get_value("country"); + if (exception_country.includes(country)) { + update_price(original_price_formatted); + return; + } + frappe.call({ + method: "lms.lms.utils.change_currency", + args: { + country: country, + amount: amount, + currency: currency, + }, + callback: (data) => { + let current_price = $(".total-price").text(); + if (current_price != data.message) { + update_price(data.message); + } + }, + }); +}; + +const update_price = (price) => { + $(".total-price").text(price); + frappe.show_alert({ + message: "Total Price has been updated.", + indicator: "yellow", + }); +}; diff --git a/lms/www/billing/billing.py b/lms/www/billing/billing.py index e88af68c..9c6c49ca 100644 --- a/lms/www/billing/billing.py +++ b/lms/www/billing/billing.py @@ -14,10 +14,17 @@ def get_context(context): validate_access(doctype, docname, module) get_billing_details(context) + context.original_amount = context.amount + context.original_currency = context.currency + context.exception_country = frappe.get_all( + "Payment Country", filters={"parent": "LMS Settings"}, pluck="country" + ) + context.amount, context.currency = check_multicurrency( context.amount, context.currency ) + context.address = get_address() if context.currency == "INR": context.amount, context.gst_applied = apply_gst(context.amount, None) @@ -75,3 +82,35 @@ def get_billing_details(context): context.title = details.title context.amount = details.amount context.currency = details.currency + + +def get_address(): + address = frappe.get_all( + "Address", + {"email_id": frappe.session.user}, + [ + "address_title as billing_name", + "address_line1", + "address_line2", + "city", + "state", + "country", + "pincode", + "phone", + ], + order_by="creation desc", + limit=1, + ) + + if not len(address): + return None + else: + address = address[0] + + if not address.address_line2: + address.address_line2 = "" + + if not address.state: + address.state = "" + + return address diff --git a/lms/www/courses/course.py b/lms/www/courses/course.py index 2666739a..b4aa476c 100644 --- a/lms/www/courses/course.py +++ b/lms/www/courses/course.py @@ -10,6 +10,7 @@ from lms.lms.utils import ( is_instructor, redirect_to_courses_list, get_average_rating, + check_multicurrency, ) @@ -60,6 +61,11 @@ def set_course_context(context, course_name): as_dict=True, ) + if course.course_price: + course.course_price, course.currency = check_multicurrency( + course.course_price, course.currency + ) + if frappe.form_dict.get("edit"): if not is_instructor(course.name) and not has_course_moderator_role(): raise frappe.PermissionError(_("You do not have permission to access this page.")) diff --git a/lms/www/courses/index.py b/lms/www/courses/index.py index 407d58e3..d887e1ca 100644 --- a/lms/www/courses/index.py +++ b/lms/www/courses/index.py @@ -7,6 +7,7 @@ from lms.lms.utils import ( has_course_moderator_role, get_courses_under_review, get_average_rating, + check_multicurrency, ) from lms.overrides.user import get_enrolled_courses, get_authored_courses @@ -58,6 +59,12 @@ def get_courses(): course.enrollment_count = frappe.db.count( "LMS Enrollment", {"course": course.name, "member_type": "Student"} ) + + if course.course_price: + course.course_price, course.currency = check_multicurrency( + course.course_price, course.currency + ) + course.avg_rating = get_average_rating(course.name) or 0 if course.upcoming: upcoming_courses.append(course)