chore: resolved conflicts

This commit is contained in:
Jannat Patel
2025-11-17 10:12:26 +05:30
80 changed files with 5586 additions and 2780 deletions

View File

@@ -0,0 +1,142 @@
<template>
<div class="flex flex-col text-base h-full">
<div class="flex items-center space-x-2 mb-8 -ml-1.5">
<ChevronLeft
class="size-5 stroke-1.5 text-ink-gray-7 cursor-pointer"
@click="emit('updateStep', 'list')"
/>
<div class="text-xl font-semibold text-ink-gray-9">
{{ data?.name ? __('Edit Coupon') : __('New Coupon') }}
</div>
</div>
<div class="space-y-4 overflow-y-auto">
<div>
<FormControl
v-model="data.enabled"
:label="__('Enabled')"
type="checkbox"
/>
</div>
<div class="grid grid-cols-2 gap-4">
<FormControl
v-model="data.code"
:label="__('Coupon Code')"
:required="true"
@input="() => (data.code = data.code.toUpperCase())"
/>
<FormControl
v-model="data.discount_type"
:label="__('Discount Type')"
:required="true"
type="select"
:options="['Percentage', 'Fixed Amount']"
/>
<FormControl
v-model="data.expires_on"
:label="__('Expires On')"
type="date"
/>
<FormControl
v-if="data.discount_type === 'Percentage'"
v-model="data.percentage_discount"
:required="true"
:label="__('Discount Percentage')"
type="number"
/>
<FormControl
v-else
v-model="data.fixed_amount_discount"
:required="true"
:label="__('Discount Amount')"
type="number"
/>
<FormControl
v-model="data.usage_limit"
:label="__('Usage Limit')"
type="number"
/>
<FormControl
v-model="data.redemptions_count"
:label="__('Redemptions Count')"
type="number"
:disabled="true"
/>
</div>
<div class="py-8">
<div class="font-semibold text-ink-gray-9 mb-2">
{{ __('Applicable For') }}
</div>
<CouponItems ref="couponItems" :data="data" :coupons="coupons" />
</div>
</div>
<div class="mt-auto space-x-2 ml-auto">
<Button variant="solid" @click="saveCoupon()">
{{ __('Save') }}
</Button>
</div>
</div>
</template>
<script setup lang="ts">
import { Button, FormControl, toast } from 'frappe-ui'
import { ref } from 'vue'
import { ChevronLeft } from 'lucide-vue-next'
import type { Coupon, Coupons } from './types'
import CouponItems from '@/components/Settings/Coupons/CouponItems.vue'
const couponItems = ref<any>(null)
const emit = defineEmits(['updateStep'])
const props = defineProps<{
coupons: Coupons
data: Coupon
}>()
const saveCoupon = () => {
if (props.data?.name) {
editCoupon()
} else {
createCoupon()
}
}
const editCoupon = () => {
props.coupons.setValue.submit(
{
...props.data,
},
{
onSuccess(data: Coupon) {
if (couponItems.value) {
couponItems.value.saveItems()
}
},
}
)
}
const createCoupon = () => {
if (couponItems.value) {
let rows = couponItems.value.saveItems()
props.data.applicable_items = rows
}
props.coupons.insert.submit(
{
...props.data,
},
{
onSuccess(data: Coupon) {
toast.success(__('Coupon created successfully'))
emit('updateStep', 'details', { ...data })
},
onError(err: any) {
toast.error(err.messages?.[0] || err.message || err)
console.error(err)
},
}
)
}
</script>

View File

@@ -0,0 +1,140 @@
<template>
<div>
<div class="relative overflow-x-auto border rounded-md">
<table class="w-full text-sm text-left text-ink-gray-5">
<thead class="text-xs text-ink-gray-7 uppercase bg-surface-gray-2">
<tr>
<td scope="col" class="px-6 py-2">
{{ __('Document Type') }}
</td>
<td scope="col" class="px-6 py-2">
{{ __('Document Name') }}
</td>
<td scope="col" class="px-6 py-2 w-16"></td>
</tr>
</thead>
<tbody>
<tr
v-for="row in rows"
class="bg-white dark:bg-gray-800 dark:border-gray-700 border-gray-200"
>
<td class="px-6 py-2">
<FormControl
type="select"
v-model="row.reference_doctype"
:options="[
{ label: 'Course', value: 'LMS Course' },
{ label: 'Batch', value: 'LMS Batch' },
]"
/>
</td>
<td class="px-6 py-2">
<Link
:doctype="row.reference_doctype"
v-model="row.reference_name"
class="bg-white"
/>
</td>
<td class="px-6 py-2">
<Button variant="ghost" @click="removeRow(row)">
<template #icon>
<X class="size-4 stroke-1.5" />
</template>
</Button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="mt-4">
<Button @click="addRow()">
<template #prefix>
<Plus class="size-4 stroke-1.5" />
</template>
{{ __('Add Row') }}
</Button>
</div>
</div>
</template>
<script setup lang="ts">
import type { ApplicableItem, Coupon, Coupons } from './types'
import { ref, watch } from 'vue'
import { Button, createListResource, FormControl } from 'frappe-ui'
import { Plus, X } from 'lucide-vue-next'
import Link from '@/components/Controls/Link.vue'
const rows = ref<
{
reference_doctype: string
reference_name: string | null
name: string | null
}[]
>([])
const props = defineProps<{
data: Coupon
coupons: Coupons
}>()
const applicableItems = createListResource({
doctype: 'LMS Coupon Item',
fields: [
'reference_doctype',
'reference_name',
'name',
'parent',
'parenttype',
'parentfield',
],
parent: 'LMS Coupon',
onSuccess(data: ApplicableItem[]) {
rows.value = data
},
})
const addRow = () => {
rows.value.push({
reference_doctype: 'LMS Course',
reference_name: null,
name: null,
})
}
watch(
() => props.data,
() => {
if (props.data?.name) {
applicableItems.update({
filters: {
parent: props.data.name,
},
})
applicableItems.reload()
} else {
addRow()
}
},
{ immediate: true }
)
const saveItems = (parent = null) => {
return rows.value
}
const removeRow = (rowToRemove: any) => {
rows.value = rows.value.filter((row) => row !== rowToRemove)
if (rowToRemove.name) {
applicableItems.delete.submit(rowToRemove.name, {
onSuccess() {
props.coupons.reload()
applicableItems.reload()
},
})
}
}
defineExpose({
saveItems,
})
</script>

View File

@@ -0,0 +1,203 @@
<template>
<div class="flex min-h-0 flex-col text-base">
<div class="flex items-center justify-between mb-5">
<div>
<div class="text-xl font-semibold mb-1 text-ink-gray-9">
{{ __(label) }}
</div>
<div class="text-ink-gray-6 leading-5">
{{ __(description) }}
</div>
</div>
<Button @click="openForm()">
<template #prefix>
<Plus class="h-3 w-3 stroke-1.5" />
</template>
{{ __('New') }}
</Button>
</div>
<div v-if="coupons.data?.length" class="overflow-y-scroll">
<ListView
:columns="columns"
:rows="coupons.data"
row-key="name"
:options="{
showTooltip: false,
selectable: true,
onRowClick: (row: Coupon) => {
openForm(row)
},
}"
>
<ListHeader
class="mb-2 grid items-center space-x-4 rounded bg-surface-gray-2 p-2"
>
</ListHeader>
<ListRows>
<ListRow :row="row" v-for="row in coupons.data" :key="row.name">
<template #default="{ column, item }">
<ListRowItem :item="row[column.key]" :align="column.align">
<div v-if="column.key == 'enabled'">
<Badge v-if="row[column.key]" theme="green">
{{ __('Enabled') }}
</Badge>
<Badge v-else theme="gray">
{{ __('Disabled') }}
</Badge>
</div>
<div v-else-if="column.key == 'expires_on'">
{{ dayjs(row[column.key]).format('DD MMM YYYY') }}
</div>
<div v-else-if="column.key == 'discount'">
<div v-if="row['discount_type'] == 'Percentage'">
{{ row['percentage_discount'] }}%
</div>
<div v-else-if="row['discount_type'] == 'Fixed Amount'">
{{ row['fixed_amount_discount'] }}/-
</div>
</div>
<div v-else class="leading-5 text-sm">
{{ row[column.key] }}
</div>
</ListRowItem>
</template>
</ListRow>
</ListRows>
<ListSelectBanner>
<template #actions="{ unselectAll, selections }">
<div class="flex gap-2">
<Button
variant="ghost"
@click="confirmDeletion(selections, unselectAll)"
>
<Trash2 class="h-4 w-4 stroke-1.5" />
</Button>
</div>
</template>
</ListSelectBanner>
</ListView>
</div>
<div v-else class="text-center text-ink-gray-6 italic mt-40">
{{ __('No coupons created yet.') }}
</div>
</div>
</template>
<script setup lang="ts">
import {
Badge,
Button,
call,
createListResource,
FeatherIcon,
ListView,
ListHeader,
ListHeaderItem,
ListRows,
ListRow,
ListRowItem,
ListSelectBanner,
toast,
} from 'frappe-ui'
import { computed, getCurrentInstance, inject, ref } from 'vue'
import { Plus, Trash2 } from 'lucide-vue-next'
import type { Coupon, Coupons } from './types'
const dayjs = inject('$dayjs') as typeof import('dayjs')
const app = getCurrentInstance()
const $dialog = app?.appContext.config.globalProperties.$dialog
const emit = defineEmits(['updateStep'])
const props = defineProps<{
label: string
description: string
coupons: Coupons
}>()
const openForm = (coupon: Coupon = {} as Coupon) => {
emit('updateStep', 'details', { ...coupon })
}
const confirmDeletion = (selections: any[], unselectAll: () => void) => {
if (selections.length === 0) {
toast.info(__('No coupons selected for deletion'))
return
}
$dialog({
title: __('Delete this coupon?'),
message: __(
'This will permanently delete the coupon and the code will no longer be valid.'
),
actions: [
{
label: __('Delete'),
theme: 'red',
variant: 'solid',
onClick({ close }: { close: () => void }) {
call('lms.lms.api.delete_documents', {
doctype: 'LMS Coupon',
documents: Array.from(selections),
}).then((data: any) => {
toast.success(__('Coupon(s) deleted successfully'))
coupons.reload()
unselectAll()
close()
})
},
},
],
})
}
function trashCoupon(name, close) {
call('frappe.client.delete', { doctype: 'LMS Coupon', name }).then(() => {
toast.success(__('Coupon deleted successfully'))
coupons.reload()
if (typeof close === 'function') close()
})
}
const columns = computed(() => {
return [
{
label: __('Code'),
key: 'code',
icon: 'tag',
width: '150px',
},
{
label: __('Discount'),
key: 'discount',
align: 'center',
width: '80px',
icon: 'dollar-sign',
},
{
label: __('Expires On'),
key: 'expires_on',
width: '120px',
icon: 'calendar',
},
{
label: __('Usage Limit'),
key: 'usage_limit',
align: 'center',
width: '100px',
icon: 'hash',
},
{
label: __('Redemption Count'),
key: 'redemption_count',
align: 'center',
width: '100px',
icon: 'users',
},
{
label: __('Enabled'),
key: 'enabled',
align: 'center',
icon: 'check-square',
},
]
})
</script>

View File

@@ -0,0 +1,53 @@
<template>
<CouponList
v-if="step === 'list'"
:label="props.label"
:description="props.description"
:coupons="coupons"
@updateStep="updateStep"
/>
<CouponDetails
v-else-if="step == 'details'"
:coupons="coupons"
:data="data"
@updateStep="updateStep"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { createListResource } from 'frappe-ui'
import CouponList from '@/components/Settings/Coupons/CouponList.vue'
import CouponDetails from '@/components/Settings/Coupons/CouponDetails.vue'
import type { Coupon } from './types'
const step = ref('list')
const data = ref<Coupon | null>(null)
const props = defineProps<{
label: string
description: string
}>()
const updateStep = (newStep: 'list' | 'new' | 'edit', newData: Coupon) => {
step.value = newStep
if (newData) {
data.value = newData
}
}
const coupons = createListResource({
doctype: 'LMS Coupon',
fields: [
'name',
'code',
'discount_type',
'percentage_discount',
'fixed_amount_discount',
'expires_on',
'usage_limit',
'redemption_count',
'enabled',
],
auto: true,
})
</script>

View File

@@ -0,0 +1,30 @@
export interface Coupon {
name: string;
enabled: boolean;
code: string;
discount_type: 'Percentage' | 'Fixed Amount';
percentage_discount?: number;
fixed_amount_discount?: number;
expires_on?: string;
description?: string;
usage_limit?: number;
redemptions_count: number;
applicable_items: ApplicableItem[];
}
export type ApplicableItem = {
reference_doctype: "LMS Course" | "LMS Batch";
reference_name: string;
name: string;
parent: string;
parenttype: "LMS Coupon";
parentfield: "applicable_items";
}
export interface Coupons {
data: Coupon[];
update: (args: { filters: any[] }) => void;
insert: { submit: (params: Coupon, options: { onSuccess: (data: Coupon) => void; onError?: (err: any) => void }) => void };
setValue: { submit: (params: Coupon, options: { onSuccess: (data: Coupon) => void; onError?: (err: any) => void }) => void };
reload: () => void;
}

View File

@@ -147,6 +147,8 @@ const columns = computed(() => {
} else {
if (field.type == 'checkbox') {
field.value = props.data[field.name] ? true : false
} else {
field.value = props.data[field.name]
}
currentColumn.push(field)
}

View File

@@ -29,7 +29,7 @@
<div
v-if="activeTab && data.doc"
:key="activeTab.label"
class="flex flex-1 flex-col px-10 py-8 bg-surface-modal overflow-x-auto"
class="flex flex-1 flex-col p-8 bg-surface-modal overflow-x-auto"
>
<component
v-if="activeTab.template"
@@ -79,7 +79,8 @@ import Categories from '@/components/Settings/Categories.vue'
import EmailTemplates from '@/components/Settings/EmailTemplates.vue'
import BrandSettings from '@/components/Settings/BrandSettings.vue'
import PaymentGateways from '@/components/Settings/PaymentGateways.vue'
import Transactions from '@/components/Settings/Transactions.vue'
import Coupons from '@/components/Settings/Coupons/Coupons.vue'
import Transactions from '@/components/Settings/Transactions/Transactions.vue'
import ZoomSettings from '@/components/Settings/ZoomSettings.vue'
import Badges from '@/components/Settings/Badges.vue'
@@ -286,6 +287,12 @@ const tabsStructure = computed(() => {
template: markRaw(Transactions),
description: 'View all your payment transactions',
},
{
label: 'Coupons',
icon: 'Ticket',
template: markRaw(Coupons),
description: 'Manage discount coupons for courses and batches',
},
],
},
{

View File

@@ -1,152 +0,0 @@
<template>
<Dialog
v-model="show"
:options="{
title: __('Transaction Details'),
size: '3xl',
}"
>
<template #body-content>
<div v-if="transactionData" class="text-base">
<div class="grid grid-cols-3 gap-5 mt-5">
<FormControl
:label="__('Payment Received')"
type="checkbox"
v-model="transactionData.payment_received"
/>
<FormControl
:label="__('Payment For Certificate')"
type="checkbox"
v-model="transactionData.payment_for_certificate"
/>
</div>
<div class="grid grid-cols-3 gap-5 mt-5">
<Link
:label="__('Member')"
doctype="User"
v-model="transactionData.member"
/>
<FormControl
:label="__('Billing Name')"
v-model="transactionData.billing_name"
/>
<Link
:label="__('Source')"
v-model="transactionData.source"
doctype="LMS Source"
/>
</div>
<div class="font-semibold mt-10">
{{ __('Payment Details') }}
</div>
<div class="grid grid-cols-3 gap-5 mt-5">
<Link
:label="__('Payment For Document Type')"
v-model="transactionData.payment_for_document_type"
doctype="DocType"
/>
<Link
:label="__('Payment For Document')"
v-model="transactionData.payment_for_document"
:doctype="transactionData.payment_for_document_type"
/>
<Link
:label="__('Address')"
v-model="transactionData.address"
doctype="Address"
/>
</div>
<div class="grid grid-cols-3 gap-5 mt-5">
<Link
:label="__('Currency')"
v-model="transactionData.currency"
doctype="Currency"
/>
<FormControl :label="__('Amount')" v-model="transactionData.amount" />
<FormControl
:label="__('Order ID')"
v-model="transactionData.order_id"
/>
</div>
<div class="grid grid-cols-3 gap-5 mt-5">
<FormControl :label="__('GSTIN')" v-model="transactionData.gstin" />
<FormControl :label="__('PAN')" v-model="transactionData.pan" />
<FormControl
:label="__('Payment ID')"
v-model="transactionData.payment_id"
/>
</div>
</div>
</template>
<template #actions="{ close }">
<div class="space-x-2 pb-5 float-right">
<Button @click="openDetails(close)">
{{ __('Open the ') }}
{{
transaction.payment_for_document_type == 'LMS Course'
? __('Course')
: __('Batch')
}}
</Button>
<Button variant="solid" @click="saveTransaction(close)">
{{ __('Save') }}
</Button>
</div>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { Dialog, FormControl, Button } from 'frappe-ui'
import { useRouter } from 'vue-router'
import { ref, watch } from 'vue'
import Link from '@/components/Controls/Link.vue'
const show = defineModel<boolean>({ required: true, default: false })
const transactions = defineModel<any>('transactions')
const router = useRouter()
const showModal = defineModel('show')
const transactionData = ref<{ [key: string]: any } | null>(null)
const props = defineProps<{
transaction: { [key: string]: any } | null
}>()
watch(
() => props.transaction,
(newVal) => {
transactionData.value = newVal ? { ...newVal } : null
},
{ immediate: true }
)
const saveTransaction = (close: () => void) => {
transactions.value.setValue
.submit({
...transactionData.value,
})
.then(() => {
close()
})
}
const openDetails = (close: Function) => {
if (props.transaction) {
const docType = props.transaction.payment_for_document_type
const docName = props.transaction.payment_for_document
if (docType && docName) {
router.push({
name: docType == 'LMS Course' ? 'CourseDetail' : 'BatchDetail',
params: {
[docType == 'LMS Course' ? 'courseName' : 'batchName']: docName,
},
})
}
}
close()
showModal.value = false
}
</script>

View File

@@ -0,0 +1,184 @@
<template>
<div class="flex flex-col h-full text-base">
<div class="flex items-center space-x-2 mb-8 -ml-1.5">
<ChevronLeft
class="size-5 stroke-1.5 text-ink-gray-7 cursor-pointer"
@click="emit('updateStep', 'list')"
/>
<div class="text-xl font-semibold text-ink-gray-9">
{{ __('Transaction Details') }}
</div>
</div>
<div v-if="transactionData" class="overflow-y-auto">
<div class="grid grid-cols-3 gap-5">
<FormControl
:label="__('Payment Received')"
type="checkbox"
v-model="transactionData.payment_received"
/>
<FormControl
:label="__('Payment For Certificate')"
type="checkbox"
v-model="transactionData.payment_for_certificate"
/>
</div>
<div class="grid grid-cols-3 gap-5 mt-5">
<Link
:label="__('Member')"
doctype="User"
v-model="transactionData.member"
/>
<FormControl
:label="__('Billing Name')"
v-model="transactionData.billing_name"
/>
<Link
:label="__('Source')"
v-model="transactionData.source"
doctype="LMS Source"
/>
<Link
:label="__('Payment For Document Type')"
v-model="transactionData.payment_for_document_type"
doctype="DocType"
/>
<Link
:label="__('Payment For Document')"
v-model="transactionData.payment_for_document"
:doctype="transactionData.payment_for_document_type"
/>
</div>
<div class="font-semibold mt-10">
{{ __('Payment Details') }}
</div>
<div class="grid grid-cols-3 gap-5 mt-5">
<Link
:label="__('Currency')"
v-model="transactionData.currency"
doctype="Currency"
/>
<FormControl :label="__('Amount')" v-model="transactionData.amount" />
<FormControl
v-if="transactionData.amount_with_gst"
:label="__('Amount with GST')"
v-model="transactionData.amount_with_gst"
/>
</div>
<div v-if="transactionData.coupon">
<div class="font-semibold mt-10">
{{ __('Coupon Details') }}
</div>
<div class="grid grid-cols-3 gap-5 mt-5">
<FormControl
v-if="transactionData.coupon"
:label="__('Coupon Code')"
v-model="transactionData.coupon"
/>
<FormControl
v-if="transactionData.coupon"
:label="__('Coupon Code')"
v-model="transactionData.coupon_code"
/>
<FormControl
v-if="transactionData.coupon"
:label="__('Discount Amount')"
v-model="transactionData.discount_amount"
/>
<FormControl
v-if="transactionData.coupon"
:label="__('Original Amount')"
v-model="transactionData.original_amount"
/>
</div>
</div>
<div class="font-semibold mt-10">
{{ __('Billing Details') }}
</div>
<div class="grid grid-cols-3 gap-5 mt-5">
<Link
:label="__('Address')"
v-model="transactionData.address"
doctype="Address"
/>
<FormControl :label="__('GSTIN')" v-model="transactionData.gstin" />
<FormControl :label="__('PAN')" v-model="transactionData.pan" />
<FormControl
:label="__('Payment ID')"
v-model="transactionData.payment_id"
/>
<FormControl
:label="__('Order ID')"
v-model="transactionData.order_id"
/>
</div>
</div>
<div class="space-x-2 mt-auto ml-auto">
<Button @click="openDetails()">
{{ __('Open the ') }}
{{
data.payment_for_document_type == 'LMS Course'
? __('Course')
: __('Batch')
}}
</Button>
<Button variant="solid" @click="saveTransaction()">
{{ __('Save') }}
</Button>
</div>
</div>
</template>
<script setup lang="ts">
import { Button, FormControl } from 'frappe-ui'
import { useRouter } from 'vue-router'
import { ref, watch } from 'vue'
import { ChevronLeft } from 'lucide-vue-next'
import Link from '@/components/Controls/Link.vue'
const router = useRouter()
const transactionData = ref<{ [key: string]: any } | null>(null)
const emit = defineEmits(['updateStep'])
const show = defineModel('show')
const props = defineProps<{
transactions: any
data: any
}>()
watch(
() => props.data,
(newVal) => {
transactionData.value = newVal ? { ...newVal } : null
},
{ immediate: true }
)
const saveTransaction = (close: () => void) => {
props.transactions.value.setValue
.submit({
...transactionData.value,
})
.then(() => {
close()
})
}
const openDetails = () => {
if (props.data) {
const docType = props.data.payment_for_document_type
const docName = props.data.payment_for_document
if (docType && docName) {
router.push({
name: docType == 'LMS Course' ? 'CourseDetail' : 'BatchDetail',
params: {
[docType == 'LMS Course' ? 'courseName' : 'batchName']: docName,
},
})
}
show.value = false
}
}
</script>

View File

@@ -96,17 +96,10 @@
</div>
</div>
</div>
<TransactionDetails
v-model="showForm"
:transaction="currentTransaction"
v-model:transactions="transactions"
v-model:show="show"
/>
</template>
<script setup lang="ts">
import {
Button,
createListResource,
ListView,
ListHeader,
ListHeaderItem,
@@ -118,50 +111,19 @@ import {
} from 'frappe-ui'
import { computed, ref, watch } from 'vue'
import { RefreshCw } from 'lucide-vue-next'
import TransactionDetails from './TransactionDetails.vue'
import Link from '@/components/Controls/Link.vue'
const showForm = ref(false)
const currentTransaction = ref<{ [key: string]: any } | null>(null)
const show = defineModel('show')
const billingName = ref(null)
const paymentReceived = ref(false)
const paymentForCertificate = ref(false)
const member = ref(null)
const emit = defineEmits(['updateStep'])
const props = defineProps({
label: {
type: String,
required: true,
},
description: {
type: String,
default: '',
},
})
const transactions = createListResource({
doctype: 'LMS Payment',
fields: [
'name',
'member',
'billing_name',
'source',
'payment_for_document_type',
'payment_for_document',
'payment_received',
'payment_for_certificate',
'currency',
'amount',
'order_id',
'payment_id',
'gstin',
'pan',
'address',
],
auto: true,
orderBy: 'modified desc',
})
const props = defineProps<{
label: string
description: string
transactions: any
}>()
watch(
[billingName, member, paymentReceived, paymentForCertificate],
@@ -171,7 +133,7 @@ watch(
newPaymentReceived,
newPaymentForCertificate,
]) => {
transactions.update({
props.transactions.update({
filters: [
newBillingName ? [['billing_name', 'like', `%${newBillingName}%`]] : [],
newMember ? [['member', '=', newMember]] : [],
@@ -183,14 +145,13 @@ watch(
: [],
].flat(),
})
transactions.reload()
props.transactions.reload()
},
{ immediate: true }
)
const openForm = (transaction: { [key: string]: any }) => {
currentTransaction.value = transaction
showForm.value = true
emit('updateStep', 'details', { ...transaction })
}
const getCurrencySymbol = (currency: string) => {

View File

@@ -0,0 +1,66 @@
<template>
<TransactionList
v-if="step === 'list'"
:label="props.label"
:description="props.description"
:transactions="transactions"
@updateStep="updateStep"
/>
<TransactionDetails
v-else-if="step == 'details'"
:transactions="transactions"
:data="data"
v-model:show="show"
@updateStep="updateStep"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { createListResource } from 'frappe-ui'
import TransactionList from '@/components/Settings/Transactions/TransactionList.vue'
import TransactionDetails from '@/components/Settings/Transactions/TransactionDetails.vue'
const step = ref('list')
const data = ref<any | null>(null)
const show = defineModel('show')
const props = defineProps<{
label: string
description: string
}>()
const updateStep = (newStep: 'list' | 'new' | 'edit', newData: any) => {
step.value = newStep
if (newData) {
data.value = newData
}
}
const transactions = createListResource({
doctype: 'LMS Payment',
fields: [
'name',
'member',
'billing_name',
'source',
'payment_for_document_type',
'payment_for_document',
'payment_received',
'payment_for_certificate',
'currency',
'amount',
'amount_with_gst',
'coupon',
'coupon_code',
'discount_amount',
'original_amount',
'order_id',
'payment_id',
'gstin',
'pan',
'address',
],
auto: true,
orderBy: 'modified desc',
})
</script>