chore: applied pre-commit hooks

This commit is contained in:
Joedeep Singh
2025-10-13 14:06:37 +00:00
parent cabb499a43
commit 99c448e0e5
10 changed files with 285 additions and 198 deletions

View File

@@ -2,7 +2,15 @@
<Dialog v-model="show" :options="{ title: dialogTitle, size: '3xl' }"> <Dialog v-model="show" :options="{ title: dialogTitle, size: '3xl' }">
<template #body-content> <template #body-content>
<div class="grid grid-cols-2 gap-4 pt-4"> <div class="grid grid-cols-2 gap-4 pt-4">
<FormControl v-model="doc.code" :label="__('Coupon Code')" :required="true" pattern="^[A-Za-z0-9]+$" minlength="6" @beforeinput="handleCodeInput" @input="doc.code = $event.target.value.toUpperCase()" /> <FormControl
v-model="doc.code"
:label="__('Coupon Code')"
:required="true"
pattern="^[A-Za-z0-9]+$"
minlength="6"
@beforeinput="handleCodeInput"
@input="doc.code = $event.target.value.toUpperCase()"
/>
<FormControl <FormControl
v-model="doc.discount_type" v-model="doc.discount_type"
:label="__('Discount Type')" :label="__('Discount Type')"
@@ -38,14 +46,33 @@
/> />
<Switch v-model="doc.active" :label="__('Active')" /> <Switch v-model="doc.active" :label="__('Active')" />
<div class="col-span-2"> <div class="col-span-2">
<div class="text-md font-medium text-ink-gray-7 mb-1 mt-2">{{ __('Select Courses/Batches') }}<span class="text-ink-red-3">*</span></div> <div class="text-md font-medium text-ink-gray-7 mb-1 mt-2">
{{ __('Select Courses/Batches')
}}<span class="text-ink-red-3">*</span>
</div>
<div class="space-y-2"> <div class="space-y-2">
<div v-for="(row, idx) in doc.applicable_items" :key="idx" class="flex gap-2 items-end"> <div
<FormControl class="w-28" v-model="row.reference_doctype" :label="__('Type')" type="select" :options="[ v-for="(row, idx) in doc.applicable_items"
{ label: 'Course ', value: 'LMS Course' }, :key="idx"
{ label: 'Batch ', value: 'LMS Batch' } class="flex gap-2 items-end"
]" /> >
<Link class="min-w-40" :doctype="row.reference_doctype || 'LMS Course'" :label="__('Name')" :value="row.reference_name" @change="(opt) => (row.reference_name = opt)" /> <FormControl
class="w-28"
v-model="row.reference_doctype"
:label="__('Type')"
type="select"
:options="[
{ label: 'Course ', value: 'LMS Course' },
{ label: 'Batch ', value: 'LMS Batch' },
]"
/>
<Link
class="min-w-40"
:doctype="row.reference_doctype || 'LMS Course'"
:label="__('Name')"
:value="row.reference_name"
@change="(opt) => (row.reference_name = opt)"
/>
<Button variant="subtle" @click="removeRow(idx)"> <Button variant="subtle" @click="removeRow(idx)">
<X class="h-3 w-3" /> <X class="h-3 w-3" />
</Button> </Button>
@@ -60,7 +87,9 @@
</template> </template>
<template #actions> <template #actions>
<div class="pb-5 float-right space-x-2"> <div class="pb-5 float-right space-x-2">
<Button variant="outline" @click="show = false">{{ __('Cancel') }}</Button> <Button variant="outline" @click="show = false">{{
__('Cancel')
}}</Button>
<Button variant="solid" @click="save">{{ __('Save') }}</Button> <Button variant="solid" @click="save">{{ __('Save') }}</Button>
</div> </div>
</template> </template>
@@ -87,7 +116,9 @@ const doc = ref({
applicable_items: [], applicable_items: [],
}) })
const dialogTitle = computed(() => (props.couponId === 'new' ? __('New Coupon') : __('Edit Coupon'))) const dialogTitle = computed(() =>
props.couponId === 'new' ? __('New Coupon') : __('Edit Coupon')
)
const getDoc = createResource({ const getDoc = createResource({
url: 'frappe.client.get', url: 'frappe.client.get',
@@ -106,14 +137,22 @@ watch(
if (props.couponId && props.couponId !== 'new') { if (props.couponId && props.couponId !== 'new') {
getDoc.submit() getDoc.submit()
} else { } else {
doc.value = { code: '', discount_type: 'Percent', active: 1, applicable_items: [] } doc.value = {
code: '',
discount_type: 'Percent',
active: 1,
applicable_items: [],
}
} }
} }
} }
) )
function addRow() { function addRow() {
doc.value.applicable_items.push({ reference_doctype: 'LMS Course', reference_name: null }) doc.value.applicable_items.push({
reference_doctype: 'LMS Course',
reference_name: null,
})
} }
function removeRow(idx) { function removeRow(idx) {
doc.value.applicable_items.splice(idx, 1) doc.value.applicable_items.splice(idx, 1)
@@ -141,28 +180,33 @@ function handleCodeInput(event) {
function save() { function save() {
if (props.couponId && props.couponId !== 'new') { if (props.couponId && props.couponId !== 'new') {
saveDoc.submit({}, { saveDoc.submit(
onSuccess() { {},
toast.success(__('Saved')) {
show.value = false onSuccess() {
emit('saved') toast.success(__('Saved'))
}, show.value = false
onError(err) { emit('saved')
toast.error(err.messages?.[0] || err.message || err) },
onError(err) {
toast.error(err.messages?.[0] || err.message || err)
},
} }
}) )
} else { } else {
insertDoc.submit({}, { insertDoc.submit(
onSuccess() { {},
toast.success(__('Saved')) {
show.value = false onSuccess() {
emit('saved') toast.success(__('Saved'))
}, show.value = false
onError(err) { emit('saved')
toast.error(err.messages?.[0] || err.message || err) },
onError(err) {
toast.error(err.messages?.[0] || err.message || err)
},
} }
}) )
} }
} }
</script> </script>

View File

@@ -27,36 +27,49 @@
<th class="text-left p-2">{{ __('Expires On') }}</th> <th class="text-left p-2">{{ __('Expires On') }}</th>
<th class="text-left p-2">{{ __('Usage') }}</th> <th class="text-left p-2">{{ __('Usage') }}</th>
<th class="text-left p-2">{{ __('Active') }}</th> <th class="text-left p-2">{{ __('Active') }}</th>
<th class="text-right p-2 w-8"></th> <th class="text-right p-2 w-8"></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="row in coupons.data" :key="row.name" class="hover:bg-surface-gray-2 cursor-pointer" @click="openForm(row.name)"> <tr
v-for="row in coupons.data"
:key="row.name"
class="hover:bg-surface-gray-2 cursor-pointer"
@click="openForm(row.name)"
>
<td class="p-2">{{ row.code }}</td> <td class="p-2">{{ row.code }}</td>
<td class="p-2">{{ row.discount_type }}</td> <td class="p-2">{{ row.discount_type }}</td>
<td class="p-2"> <td class="p-2">
<span v-if="row.discount_type === 'Percent'">{{ row.percent_off }}%</span> <span v-if="row.discount_type === 'Percent'"
>{{ row.percent_off }}%</span
>
<span v-else>{{ row.amount_off }}</span> <span v-else>{{ row.amount_off }}</span>
</td> </td>
<td class="p-2">{{ row.expires_on || '-' }}</td> <td class="p-2">{{ row.expires_on || '-' }}</td>
<td class="p-2">{{ row.times_redeemed }}/{{ row.usage_limit || '∞' }}</td> <td class="p-2">
{{ row.times_redeemed }}/{{ row.usage_limit || '∞' }}
</td>
<td class="p-2"> <td class="p-2">
<Badge v-if="row.active" theme="green">{{ __('Enabled') }}</Badge> <Badge v-if="row.active" theme="green">{{ __('Enabled') }}</Badge>
<Badge v-else theme="gray">{{ __('Disabled') }}</Badge> <Badge v-else theme="gray">{{ __('Disabled') }}</Badge>
</td> </td>
<td class="p-2 text-right" @click.stop> <td class="p-2 text-right" @click.stop>
<Button variant="ghost" @click="confirmDelete(row)"> <Button variant="ghost" @click="confirmDelete(row)">
<template #icon> <template #icon>
<Trash2 class="h-4 w-4 stroke-1.5 text-ink-red-4" /> <Trash2 class="h-4 w-4 stroke-1.5 text-ink-red-4" />
</template> </template>
</Button> </Button>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<CouponDetails v-model="showDialog" :coupon-id="selected" @saved="onSaved" /> <CouponDetails
v-model="showDialog"
:coupon-id="selected"
@saved="onSaved"
/>
</div> </div>
</template> </template>
<script setup> <script setup>
@@ -104,7 +117,9 @@ function onSaved() {
function confirmDelete(row) { function confirmDelete(row) {
$dialog({ $dialog({
title: __('Delete this coupon?'), title: __('Delete this coupon?'),
message: __('This will permanently delete the coupon and the code will no longer work. Are you sure?'), message: __(
'This will permanently delete the coupon and the code will no longer work. Are you sure?'
),
actions: [ actions: [
{ {
label: __('Delete'), label: __('Delete'),
@@ -127,4 +142,3 @@ function trashCoupon(name, close) {
}) })
} }
</script> </script>

View File

@@ -88,7 +88,10 @@
:disabled="true" :disabled="true"
/> />
<FormControl <FormControl
v-if="Number(transactionData.discount_amount) || Number(transactionData.gst_amount)" v-if="
Number(transactionData.discount_amount) ||
Number(transactionData.gst_amount)
"
:label="__('Total Amount')" :label="__('Total Amount')"
v-model="transactionData.total_amount" v-model="transactionData.total_amount"
:disabled="true" :disabled="true"

View File

@@ -73,7 +73,8 @@
:disabled="true" :disabled="true"
/> />
<div v-else-if="column.key == 'amount'"> <div v-else-if="column.key == 'amount'">
{{ getCurrencySymbol(row['currency']) }} {{ row['total_amount'] }} {{ getCurrencySymbol(row['currency']) }}
{{ row['total_amount'] }}
</div> </div>
<div v-else class="leading-5 text-sm"> <div v-else class="leading-5 text-sm">
{{ row[column.key] }} {{ row[column.key] }}

View File

@@ -35,7 +35,10 @@
{{ orderSummary.data.original_amount_formatted }} {{ orderSummary.data.original_amount_formatted }}
</div> </div>
</div> </div>
<div v-if="orderSummary.data.discount_amount" class="flex items-center justify-between mt-2"> <div
v-if="orderSummary.data.discount_amount"
class="flex items-center justify-between mt-2"
>
<div class="text-ink-gray-5">{{ __('Discount') }}</div> <div class="text-ink-gray-5">{{ __('Discount') }}</div>
<div>-{{ orderSummary.data.discount_amount_formatted }}</div> <div>-{{ orderSummary.data.discount_amount_formatted }}</div>
</div> </div>
@@ -61,11 +64,32 @@
</div> </div>
</div> </div>
<div class="mb-5"> <div class="mb-5">
<div class="flex items-center gap-3 mt-2 flex-wrap md:flex-nowrap" v-if="props.type !== 'certificate'"> <div
<span class="text-ink-gray-5 text-xs shrink-0">{{ __('Coupon') }}</span> class="flex items-center gap-3 mt-2 flex-wrap md:flex-nowrap"
<FormControl class="flex-1 min-w-0 [&_input]:!bg-[#fefefe]" v-model="couponCode" :disabled="appliedCoupon" @input="couponCode = $event.target.value.toUpperCase()"/> v-if="props.type !== 'certificate'"
<Button v-if="!appliedCoupon" @click="applyCouponCode" variant="outline">{{ __('Apply') }}</Button> >
<Button v-if="appliedCoupon" @click="removeCoupon" variant="subtle" class="bg-red-200"><X class="h-4.5 w-4.5" /></Button> <span class="text-ink-gray-5 text-xs shrink-0">{{
__('Coupon')
}}</span>
<FormControl
class="flex-1 min-w-0 [&_input]:!bg-[#fefefe]"
v-model="couponCode"
:disabled="appliedCoupon"
@input="couponCode = $event.target.value.toUpperCase()"
/>
<Button
v-if="!appliedCoupon"
@click="applyCouponCode"
variant="outline"
>{{ __('Apply') }}</Button
>
<Button
v-if="appliedCoupon"
@click="removeCoupon"
variant="subtle"
class="bg-red-200"
><X class="h-4.5 w-4.5"
/></Button>
</div> </div>
</div> </div>
</div> </div>
@@ -268,7 +292,7 @@ const setBillingDetails = (data) => {
const paymentLink = createResource({ const paymentLink = createResource({
url: 'lms.lms.payments.get_payment_link', url: 'lms.lms.payments.get_payment_link',
makeParams(values) { makeParams(values) {
let data={ let data = {
doctype: props.type == 'batch' ? 'LMS Batch' : 'LMS Course', doctype: props.type == 'batch' ? 'LMS Batch' : 'LMS Course',
docname: props.name, docname: props.name,
title: orderSummary.data.title, title: orderSummary.data.title,

View File

@@ -2,75 +2,75 @@
# For license information, please see license.txt # For license information, please see license.txt
import frappe import frappe
from frappe.model.document import Document
from frappe import _ from frappe import _
from frappe.model.document import Document
from frappe.utils import nowdate from frappe.utils import nowdate
class LMSCoupon(Document): class LMSCoupon(Document):
def validate(self): def validate(self):
if self.code: if self.code:
self.code = self.code.strip().upper() self.code = self.code.strip().upper()
if not self.code: if not self.code:
frappe.throw(_("Coupon code is required")) frappe.throw(_("Coupon code is required"))
if len(self.code) < 6: if len(self.code) < 6:
frappe.throw(_("Coupon code must be atleast 6 characters")) frappe.throw(_("Coupon code must be atleast 6 characters"))
if self.name: if self.name:
existing = frappe.db.exists( existing = frappe.db.exists(
"LMS Coupon", "LMS Coupon",
{ {
"code": self.code, "code": self.code,
"name": ["!=", self.name], "name": ["!=", self.name],
}, },
) )
else: else:
existing = frappe.db.exists("LMS Coupon", {"code": self.code}) existing = frappe.db.exists("LMS Coupon", {"code": self.code})
if existing: if existing:
frappe.throw(_("Coupon code is already taken. Use a different one")) frappe.throw(_("Coupon code is already taken. Use a different one"))
if not self.discount_type: if not self.discount_type:
frappe.throw(_("Discount type is required")) frappe.throw(_("Discount type is required"))
if self.discount_type == "Percent": if self.discount_type == "Percent":
if not self.percent_off or self.percent_off == "": if not self.percent_off or self.percent_off == "":
frappe.throw(_("Discount percentage is required")) frappe.throw(_("Discount percentage is required"))
try: try:
percent_value = float(self.percent_off) percent_value = float(self.percent_off)
if not (0 < percent_value <= 100): if not (0 < percent_value <= 100):
frappe.throw(_("Discount percentage must be between 1 and 100")) frappe.throw(_("Discount percentage must be between 1 and 100"))
except (ValueError, TypeError): except (ValueError, TypeError):
frappe.throw(_("Discount percentage must be a valid number")) frappe.throw(_("Discount percentage must be a valid number"))
self.amount_off = None self.amount_off = None
if self.discount_type == "Amount": if self.discount_type == "Amount":
if not self.amount_off or self.amount_off == "": if not self.amount_off or self.amount_off == "":
frappe.throw(_("Discount amount is required")) frappe.throw(_("Discount amount is required"))
try: try:
amount_value = float(self.amount_off) amount_value = float(self.amount_off)
if amount_value < 0: if amount_value < 0:
frappe.throw(_("Discount amount cannot be negative")) frappe.throw(_("Discount amount cannot be negative"))
except (ValueError, TypeError): except (ValueError, TypeError):
frappe.throw(_("Discount amount must be a valid number")) frappe.throw(_("Discount amount must be a valid number"))
self.percent_off = None self.percent_off = None
if self.usage_limit is not None and self.usage_limit != "": if self.usage_limit is not None and self.usage_limit != "":
try: try:
usage_value = int(self.usage_limit) usage_value = int(self.usage_limit)
if usage_value < 0: if usage_value < 0:
frappe.throw(_("Usage limit cannot be negative")) frappe.throw(_("Usage limit cannot be negative"))
except (ValueError, TypeError): except (ValueError, TypeError):
frappe.throw(_("Usage limit must be a valid number")) frappe.throw(_("Usage limit must be a valid number"))
if self.expires_on and str(self.expires_on) < nowdate(): if self.expires_on and str(self.expires_on) < nowdate():
frappe.throw(_("Expiry date cannot be in the past")) frappe.throw(_("Expiry date cannot be in the past"))
if not self.get("applicable_items") or len(self.get("applicable_items")) == 0: if not self.get("applicable_items") or len(self.get("applicable_items")) == 0:
frappe.throw(_("Please select atleast one course or batch")) frappe.throw(_("Please select atleast one course or batch"))
for item in self.get("applicable_items"): for item in self.get("applicable_items"):
if not item.get("reference_name"): if not item.get("reference_name"):
frappe.throw(_("Please select a valid course or batch")) frappe.throw(_("Please select a valid course or batch"))

View File

@@ -4,7 +4,6 @@
# import frappe # import frappe
from frappe.tests import IntegrationTestCase from frappe.tests import IntegrationTestCase
# On IntegrationTestCase, the doctype test records and all # On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded # link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list # Use these module variables to add/remove to/from that list
@@ -12,7 +11,6 @@ EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"] IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
class IntegrationTestLMSCoupon(IntegrationTestCase): class IntegrationTestLMSCoupon(IntegrationTestCase):
""" """
Integration tests for LMSCoupon. Integration tests for LMSCoupon.

View File

@@ -5,7 +5,7 @@ import frappe
from frappe import _ from frappe import _
from frappe.email.doctype.email_template.email_template import get_email_template from frappe.email.doctype.email_template.email_template import get_email_template
from frappe.model.document import Document from frappe.model.document import Document
from frappe.utils import add_days, nowdate, flt from frappe.utils import add_days, flt, nowdate
class LMSPayment(Document): class LMSPayment(Document):
@@ -15,6 +15,7 @@ class LMSPayment(Document):
gst = flt(self.gst_amount or 0, self.precision("gst_amount")) gst = flt(self.gst_amount or 0, self.precision("gst_amount"))
self.total_amount = flt(amount - discount + gst, self.precision("total_amount")) self.total_amount = flt(amount - discount + gst, self.precision("total_amount"))
def send_payment_reminder(): def send_payment_reminder():
outgoing_email_account = frappe.get_cached_value( outgoing_email_account = frappe.get_cached_value(
"Email Account", {"default_outgoing": 1, "enable_outgoing": 1}, "name" "Email Account", {"default_outgoing": 1, "enable_outgoing": 1}, "name"

View File

@@ -1,5 +1,6 @@
import frappe import frappe
def get_payment_gateway(): def get_payment_gateway():
return frappe.db.get_single_value("LMS Settings", "payment_gateway") return frappe.db.get_single_value("LMS Settings", "payment_gateway")
@@ -18,17 +19,17 @@ def validate_currency(payment_gateway, currency):
@frappe.whitelist() @frappe.whitelist()
def get_payment_link( def get_payment_link(
doctype, doctype,
docname, docname,
title, title,
amount, amount,
discount_amount, discount_amount,
gst_amount, gst_amount,
currency, currency,
address, address,
redirect_to, redirect_to,
payment_for_certificate, payment_for_certificate,
coupon_code=None, coupon_code=None,
): ):
payment_gateway = get_payment_gateway() payment_gateway = get_payment_gateway()
address = frappe._dict(address) address = frappe._dict(address)
@@ -37,21 +38,22 @@ def get_payment_link(
if doctype in ["LMS Course", "LMS Batch"] and coupon_code: if doctype in ["LMS Course", "LMS Batch"] and coupon_code:
try: try:
from lms.lms.utils import apply_coupon from lms.lms.utils import apply_coupon
coupon_context = apply_coupon(doctype, docname, coupon_code) coupon_context = apply_coupon(doctype, docname, coupon_code)
except Exception: except Exception:
pass pass
payment = record_payment( payment = record_payment(
address, address,
doctype, doctype,
docname, docname,
amount, amount,
currency, currency,
discount_amount, discount_amount,
gst_amount, gst_amount,
payment_for_certificate, payment_for_certificate,
coupon_context, coupon_context,
) )
controller = get_controller(payment_gateway) controller = get_controller(payment_gateway)
payment_details = { payment_details = {
@@ -79,15 +81,15 @@ def get_payment_link(
def record_payment( def record_payment(
address, address,
doctype, doctype,
docname, docname,
amount, amount,
currency, currency,
discount_amount=0, discount_amount=0,
gst_amount=0, gst_amount=0,
payment_for_certificate=0, payment_for_certificate=0,
coupon_context=None, coupon_context=None,
): ):
address = frappe._dict(address) address = frappe._dict(address)
address_name = save_address(address) address_name = save_address(address)

View File

@@ -953,74 +953,74 @@ def get_current_exchange_rate(source, target="USD"):
@frappe.whitelist() @frappe.whitelist()
def apply_coupon(doctype, docname, code, country=None): def apply_coupon(doctype, docname, code, country=None):
# Validate doctype # Validate doctype
if doctype not in ["LMS Course", "LMS Batch"]: if doctype not in ["LMS Course", "LMS Batch"]:
frappe.throw(_("Invalid doctype for coupon application.")) frappe.throw(_("Invalid doctype for coupon application."))
if not code: if not code:
frappe.throw(_("Coupon code is required.")) frappe.throw(_("Coupon code is required."))
summary = get_order_summary(doctype, docname, country) summary = get_order_summary(doctype, docname, country)
base_amount = summary.original_amount base_amount = summary.original_amount
currency = summary.currency currency = summary.currency
# Fetch coupon case-insensitively # Fetch coupon case-insensitively
coupon_name = frappe.db.get_value("LMS Coupon", {"code": code.strip().upper(), "active": 1}, "name") coupon_name = frappe.db.get_value("LMS Coupon", {"code": code.strip().upper(), "active": 1}, "name")
if not coupon_name: if not coupon_name:
frappe.throw(_("Invalid or inactive coupon code.")) frappe.throw(_("Invalid or inactive coupon code."))
coupon = frappe.get_doc("LMS Coupon", coupon_name) coupon = frappe.get_doc("LMS Coupon", coupon_name)
# Expiry # Expiry
if coupon.expires_on and getdate(coupon.expires_on) < getdate(): if coupon.expires_on and getdate(coupon.expires_on) < getdate():
frappe.throw(_("This coupon has expired.")) frappe.throw(_("This coupon has expired."))
# Usage limit # Usage limit
if coupon.usage_limit and cint(coupon.times_redeemed) >= cint(coupon.usage_limit): if coupon.usage_limit and cint(coupon.times_redeemed) >= cint(coupon.usage_limit):
frappe.throw(_("This coupon has reached its usage limit.")) frappe.throw(_("This coupon has reached its usage limit."))
# Applicability (if rows exist, must match; if none, applies to all) # Applicability (if rows exist, must match; if none, applies to all)
applicable = True applicable = True
if len(coupon.applicable_items): if len(coupon.applicable_items):
applicable = any( applicable = any(
(row.reference_doctype == doctype and row.reference_name == docname) (row.reference_doctype == doctype and row.reference_name == docname)
for row in coupon.applicable_items for row in coupon.applicable_items
) )
if not applicable: if not applicable:
frappe.throw(_("This coupon is not applicable to this item.")) frappe.throw(_("This coupon is not applicable to this item."))
# Compute discount before tax # Compute discount before tax
discount_amount = 0 discount_amount = 0
if coupon.discount_type == "Percent": if coupon.discount_type == "Percent":
discount_amount = cint(flt(base_amount) * flt(coupon.percent_off) / 100) discount_amount = cint(flt(base_amount) * flt(coupon.percent_off) / 100)
else: else:
discount_amount = min(flt(coupon.amount_off), flt(base_amount)) discount_amount = min(flt(coupon.amount_off), flt(base_amount))
subtotal = max(flt(base_amount) - flt(discount_amount), 0) subtotal = max(flt(base_amount) - flt(discount_amount), 0)
gst_applied = 0 gst_applied = 0
final_amount = subtotal final_amount = subtotal
if currency == "INR": if currency == "INR":
final_amount, gst_applied = apply_gst(subtotal, country) final_amount, gst_applied = apply_gst(subtotal, country)
return { return {
"title": summary.title, "title": summary.title,
"name": summary.name, "name": summary.name,
"currency": currency, "currency": currency,
"original_amount": base_amount, "original_amount": base_amount,
"original_amount_formatted": fmt_money(base_amount, 0, currency), "original_amount_formatted": fmt_money(base_amount, 0, currency),
"discount_amount": discount_amount, "discount_amount": discount_amount,
"discount_amount_formatted": fmt_money(discount_amount, 0, currency), "discount_amount_formatted": fmt_money(discount_amount, 0, currency),
"amount": final_amount, "amount": final_amount,
"gst_applied": gst_applied, "gst_applied": gst_applied,
"gst_amount_formatted": fmt_money(gst_applied, 0, currency) if gst_applied else None, "gst_amount_formatted": fmt_money(gst_applied, 0, currency) if gst_applied else None,
"total_amount_formatted": fmt_money(final_amount, 0, currency), "total_amount_formatted": fmt_money(final_amount, 0, currency),
"coupon": coupon.name, "coupon": coupon.name,
"coupon_code": coupon.code, "coupon_code": coupon.code,
"discount_type": coupon.discount_type, "discount_type": coupon.discount_type,
"discount_percent": coupon.percent_off if coupon.discount_type == "Percent" else None, "discount_percent": coupon.percent_off if coupon.discount_type == "Percent" else None,
} }
@frappe.whitelist() @frappe.whitelist()