diff --git a/lms/lms/doctype/lms_settings/lms_settings.json b/lms/lms/doctype/lms_settings/lms_settings.json index 4e1442c5..36741a4b 100644 --- a/lms/lms/doctype/lms_settings/lms_settings.json +++ b/lms/lms/doctype/lms_settings/lms_settings.json @@ -20,10 +20,13 @@ "allow_student_progress", "payment_section", "razorpay_key", - "default_currency", - "column_break_cfcv", "razorpay_secret", "apply_gst", + "column_break_cfcv", + "default_currency", + "show_usd_equivalent", + "apply_rounding", + "exception_country", "signup_settings_tab", "signup_settings_section", "terms_of_use", @@ -231,12 +234,31 @@ "fieldname": "apply_gst", "fieldtype": "Check", "label": "Apply GST for India" + }, + { + "default": "0", + "fieldname": "show_usd_equivalent", + "fieldtype": "Check", + "label": "Show USD Equivalent" + }, + { + "depends_on": "show_usd_equivalent", + "fieldname": "exception_country", + "fieldtype": "Table MultiSelect", + "label": "Maintain Original Currency", + "options": "Payment Country" + }, + { + "default": "0", + "fieldname": "apply_rounding", + "fieldtype": "Check", + "label": "Apply Rounding on Equivalent" } ], "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-08-29 09:54:48.030823", + "modified": "2023-09-11 21:56:39.996898", "modified_by": "Administrator", "module": "LMS", "name": "LMS Settings", diff --git a/lms/lms/doctype/payment_country/__init__.py b/lms/lms/doctype/payment_country/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/lms/lms/doctype/payment_country/payment_country.js b/lms/lms/doctype/payment_country/payment_country.js new file mode 100644 index 00000000..3ad2f61b --- /dev/null +++ b/lms/lms/doctype/payment_country/payment_country.js @@ -0,0 +1,8 @@ +// Copyright (c) 2023, Frappe and contributors +// For license information, please see license.txt + +// frappe.ui.form.on("Payment Country", { +// refresh(frm) { + +// }, +// }); diff --git a/lms/lms/doctype/payment_country/payment_country.json b/lms/lms/doctype/payment_country/payment_country.json new file mode 100644 index 00000000..cf493409 --- /dev/null +++ b/lms/lms/doctype/payment_country/payment_country.json @@ -0,0 +1,33 @@ +{ + "actions": [], + "allow_rename": 1, + "creation": "2023-09-11 11:53:16.253740", + "default_view": "List", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "country" + ], + "fields": [ + { + "fieldname": "country", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Country", + "options": "Country" + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2023-09-11 12:04:56.048632", + "modified_by": "Administrator", + "module": "LMS", + "name": "Payment Country", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC", + "states": [] +} \ No newline at end of file diff --git a/lms/lms/doctype/payment_country/payment_country.py b/lms/lms/doctype/payment_country/payment_country.py new file mode 100644 index 00000000..9d834847 --- /dev/null +++ b/lms/lms/doctype/payment_country/payment_country.py @@ -0,0 +1,9 @@ +# Copyright (c) 2023, Frappe and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class PaymentCountry(Document): + pass diff --git a/lms/lms/doctype/payment_country/test_payment_country.py b/lms/lms/doctype/payment_country/test_payment_country.py new file mode 100644 index 00000000..994c246d --- /dev/null +++ b/lms/lms/doctype/payment_country/test_payment_country.py @@ -0,0 +1,9 @@ +# Copyright (c) 2023, Frappe and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestPaymentCountry(FrappeTestCase): + pass diff --git a/lms/lms/utils.py b/lms/lms/utils.py index a5bc80ce..7e8147e1 100644 --- a/lms/lms/utils.py +++ b/lms/lms/utils.py @@ -3,6 +3,8 @@ import string import frappe import json import razorpay +import requests +import base64 from frappe import _ from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_result from frappe.desk.doctype.notification_log.notification_log import make_notification_logs @@ -830,19 +832,20 @@ def get_upcoming_evals(student, courses): @frappe.whitelist() -def get_payment_options(doctype, docname, phone): +def get_payment_options(doctype, docname, phone, country): if not frappe.db.exists(doctype, docname): frappe.throw(_("Invalid document provided.")) validate_phone_number(phone, True) details = get_details(doctype, docname) + details.amount, details.currency = check_multicurrency(details) + details.amount, details.gst_applied = apply_gst(details, country) - razorpay_key = frappe.db.get_single_value("LMS Settings", "razorpay_key") client = get_client() order = create_order(client, details.amount, details.currency) options = { - "key_id": razorpay_key, + "key_id": frappe.db.get_single_value("LMS Settings", "razorpay_key"), "name": frappe.db.get_single_value("Website Settings", "app_name"), "description": _("Payment for {0} course").format(details["title"]), "order_id": order["id"], @@ -857,6 +860,42 @@ def get_payment_options(doctype, docname, phone): return options +def check_multicurrency(amount, currency): + show_usd_equivalent = frappe.db.get_single_value("LMS Settings", "show_usd_equivalent") + exception_country = frappe.db.get_single_value("LMS Settings", "exception_country") + apply_rounding = frappe.db.get_single_value("LMS Settings", "apply_rounding") + country = frappe.db.get_value("User", frappe.session.user, "country") + + if not show_usd_equivalent: + return + + if currency == "USD": + return + + if exception_country and country in exception_country: + return + + exchange_rate = get_current_exchange_rate(currency, "USD") + amount = amount * exchange_rate + currency = "USD" + + if apply_rounding and amount % 100 != 0: + amount = amount + 100 - amount % 100 + + return amount, currency + + +def apply_gst(amount, country): + gst_applied = False + apply_gst = frappe.db.get_single_value("LMS Settings", "apply_gst") + + if apply_gst and country == "India": + gst_applied = True + amount = amount * 1.18 + + return amount, gst_applied + + def get_details(doctype, docname): if doctype == "LMS Course": details = frappe.db.get_value( @@ -896,8 +935,9 @@ def save_address(address): def get_client(): - razorpay_key = frappe.db.get_single_value("LMS Settings", "razorpay_key") - razorpay_secret = frappe.db.get_single_value("LMS Settings", "razorpay_secret") + settings = frappe.get_single("LMS Settings") + razorpay_key = settings.razorpay_key + razorpay_secret = settings.get_password("razorpay_secret", raise_exception=True) if not razorpay_key and not razorpay_secret: frappe.throw( @@ -946,7 +986,7 @@ def record_payment(address, response, client, doctype, docname): address = frappe._dict(json.loads(address)) address_name = save_address(address) - payment_details = get_payment_details(doctype, docname) + payment_details = get_payment_details(doctype, docname, address) payment_doc = frappe.new_doc("LMS Payment") payment_doc.update( { @@ -966,10 +1006,13 @@ def record_payment(address, response, client, doctype, docname): return payment_doc.name -def get_payment_details(doctype, docname): +def get_payment_details(doctype, docname, address): amount_field = "course_price" if doctype == "LMS Course" else "amount" amount = frappe.db.get_value(doctype, docname, amount_field) currency = frappe.db.get_value(doctype, docname, "currency") + apply_gst = frappe.db.get_single_value("LMS Settings", "apply_gst") + if apply_gst and address.country == "India": + amount = amount * 1.18 return { "amount": amount, @@ -999,3 +1042,11 @@ def add_student_to_batch(batchname, payment): ) student.save(ignore_permissions=True) return f"/batches/{batchname}" + + +def get_current_exchange_rate(source, target="USD"): + url = f"https://api.frankfurter.app/latest?from={source}&to={target}" + + response = requests.request("GET", url) + details = response.json() + return details["rates"][target] diff --git a/lms/www/billing/billing.html b/lms/www/billing/billing.html index 72643285..d9c5a956 100644 --- a/lms/www/billing/billing.html +++ b/lms/www/billing/billing.html @@ -30,7 +30,7 @@