feat: apply_gst in batches
This commit is contained in:
@@ -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",
|
||||
|
||||
0
lms/lms/doctype/payment_country/__init__.py
Normal file
0
lms/lms/doctype/payment_country/__init__.py
Normal file
8
lms/lms/doctype/payment_country/payment_country.js
Normal file
8
lms/lms/doctype/payment_country/payment_country.js
Normal file
@@ -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) {
|
||||
|
||||
// },
|
||||
// });
|
||||
33
lms/lms/doctype/payment_country/payment_country.json
Normal file
33
lms/lms/doctype/payment_country/payment_country.json
Normal file
@@ -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": []
|
||||
}
|
||||
9
lms/lms/doctype/payment_country/payment_country.py
Normal file
9
lms/lms/doctype/payment_country/payment_country.py
Normal file
@@ -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
|
||||
9
lms/lms/doctype/payment_country/test_payment_country.py
Normal file
9
lms/lms/doctype/payment_country/test_payment_country.py
Normal file
@@ -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
|
||||
@@ -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]
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<div class="">
|
||||
<div class="flex mb-2">
|
||||
<div class="field-label">
|
||||
{% set label = "Course Name" if module == "course" else "Batch Name" %}
|
||||
{% set label = "Course" if module == "course" else "Batch" %}
|
||||
{{ _(label) }} : {{ title }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -40,6 +40,11 @@
|
||||
{{ _("Total Price: ") }} {{ frappe.utils.fmt_money(amount, 2, currency) }}
|
||||
</div>
|
||||
</div>
|
||||
{% if gst_applied %}
|
||||
<span class="small mt-2">
|
||||
{{ _("18% GST included") }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
@@ -104,6 +104,7 @@ const generate_payment_link = (e) => {
|
||||
doctype: doctype,
|
||||
docname: docname,
|
||||
phone: address.phone,
|
||||
country: address.country,
|
||||
},
|
||||
callback: (data) => {
|
||||
data.message.handler = (response) => {
|
||||
|
||||
@@ -1,23 +1,30 @@
|
||||
import frappe
|
||||
from frappe import _
|
||||
from lms.lms.utils import check_multicurrency, apply_gst
|
||||
|
||||
|
||||
def get_context(context):
|
||||
module = frappe.form_dict.module
|
||||
docname = frappe.form_dict.modulename
|
||||
doctype = "LMS Course" if module == "course" else "LMS Batch"
|
||||
|
||||
context.module = module
|
||||
context.docname = docname
|
||||
context.doctype = doctype
|
||||
|
||||
validate_access(doctype, docname, module)
|
||||
get_billing_details(context)
|
||||
check_multicurrency(context)
|
||||
apply_gst(context)
|
||||
|
||||
|
||||
def validate_access(doctype, docname, module):
|
||||
if frappe.session.user == "Guest":
|
||||
raise frappe.PermissionError(_("You are not allowed to access this page."))
|
||||
|
||||
if module not in ["course", "batch"]:
|
||||
raise ValueError(_("Module is incorrect."))
|
||||
|
||||
doctype = "LMS Course" if module == "course" else "LMS Batch"
|
||||
context.module = module
|
||||
context.docname = docname
|
||||
context.doctype = doctype
|
||||
context.apply_gst = frappe.db.get_single_value("LMS Settings", "apply_gst")
|
||||
|
||||
if not frappe.db.exists(doctype, docname):
|
||||
raise ValueError(_("Module Name is incorrect or does not exist."))
|
||||
|
||||
@@ -35,37 +42,32 @@ def get_context(context):
|
||||
if membership:
|
||||
raise frappe.PermissionError(_("You are already enrolled for this batch."))
|
||||
|
||||
if doctype == "LMS Course":
|
||||
course = frappe.db.get_value(
|
||||
|
||||
def get_billing_details(context):
|
||||
if context.doctype == "LMS Course":
|
||||
details = frappe.db.get_value(
|
||||
"LMS Course",
|
||||
docname,
|
||||
["title", "name", "paid_course", "course_price", "currency"],
|
||||
context.docname,
|
||||
["title", "name", "paid_course", "course_price as amount", "currency"],
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
if not course.paid_course:
|
||||
if not details.paid_course:
|
||||
raise frappe.PermissionError(_("This course is free."))
|
||||
|
||||
context.title = course.title
|
||||
context.amount = course.course_price
|
||||
context.currency = course.currency
|
||||
|
||||
else:
|
||||
batch = frappe.db.get_value(
|
||||
details = frappe.db.get_value(
|
||||
"LMS Batch",
|
||||
docname,
|
||||
context.docname,
|
||||
["title", "name", "paid_batch", "amount", "currency"],
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
if not batch.paid_batch:
|
||||
if not details.paid_batch:
|
||||
raise frappe.PermissionError(
|
||||
_("To join this batch, please contact the Administrator.")
|
||||
)
|
||||
|
||||
context.title = batch.title
|
||||
context.amount = batch.amount
|
||||
context.currency = batch.currency
|
||||
|
||||
if context.apply_gst:
|
||||
context.gst_amount = context.amount * 1.18
|
||||
context.title = details.title
|
||||
context.amount = details.amount
|
||||
context.currency = details.currency
|
||||
|
||||
Reference in New Issue
Block a user