feat: transaction list
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="flex flex-col justify-between h-full">
|
||||
<div class="flex flex-col justify-between h-full text-base">
|
||||
<div>
|
||||
<div class="flex itemsc-center justify-between">
|
||||
<div class="text-xl font-semibold leading-none mb-1 text-ink-gray-9">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="text-xl font-semibold leading-none mb-2 text-ink-gray-9">
|
||||
{{ __(label) }}
|
||||
</div>
|
||||
<Badge
|
||||
@@ -12,7 +12,7 @@
|
||||
theme="orange"
|
||||
/>
|
||||
</div>
|
||||
<div class="text-xs text-ink-gray-5">
|
||||
<div class="text-ink-gray-6 leading-5">
|
||||
{{ __(description) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -44,7 +44,8 @@
|
||||
? { fields: activeTab.fields }
|
||||
: {}),
|
||||
...(activeTab.label == 'Evaluators' ||
|
||||
activeTab.label == 'Members'
|
||||
activeTab.label == 'Members' ||
|
||||
activeTab.label == 'Transactions'
|
||||
? { 'onUpdate:show': (val) => (show = val), show }
|
||||
: {}),
|
||||
}"
|
||||
@@ -80,6 +81,7 @@ 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 ZoomSettings from '@/components/Settings/ZoomSettings.vue'
|
||||
import Badges from '@/components/Settings/Badges.vue'
|
||||
|
||||
@@ -168,8 +170,7 @@ const tabsStructure = computed(() => {
|
||||
{
|
||||
label: 'Configuration',
|
||||
icon: 'CreditCard',
|
||||
description:
|
||||
'Configure the payment gateway and other payment related settings',
|
||||
description: 'Manage all your payment related settings and defaults',
|
||||
fields: [
|
||||
{
|
||||
label: 'Default Currency',
|
||||
@@ -209,6 +210,12 @@ const tabsStructure = computed(() => {
|
||||
template: markRaw(PaymentGateways),
|
||||
description: 'Add and manage all your payment gateways',
|
||||
},
|
||||
{
|
||||
label: 'Transactions',
|
||||
icon: 'Landmark',
|
||||
template: markRaw(Transactions),
|
||||
description: 'View all your payment transactions',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
152
frontend/src/components/Settings/TransactionDetails.vue
Normal file
152
frontend/src/components/Settings/TransactionDetails.vue
Normal file
@@ -0,0 +1,152 @@
|
||||
<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>
|
||||
241
frontend/src/components/Settings/Transactions.vue
Normal file
241
frontend/src/components/Settings/Transactions.vue
Normal file
@@ -0,0 +1,241 @@
|
||||
<template>
|
||||
<div class="flex min-h-0 flex-col text-base">
|
||||
<div class="mb-5">
|
||||
<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>
|
||||
|
||||
<div class="flex items-center space-x-5 mb-4">
|
||||
<FormControl
|
||||
v-model="billingName"
|
||||
:placeholder="__('Filter by Billing Name')"
|
||||
/>
|
||||
<Link
|
||||
v-model="member"
|
||||
doctype="User"
|
||||
:placeholder="__('Filter by Member')"
|
||||
/>
|
||||
<FormControl
|
||||
v-model="paymentReceived"
|
||||
type="checkbox"
|
||||
:label="__('Payment Received')"
|
||||
/>
|
||||
<FormControl
|
||||
v-model="paymentForCertificate"
|
||||
type="checkbox"
|
||||
:label="__('Payment for Certificate')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="transactions.data?.length" class="overflow-y-scroll">
|
||||
<ListView
|
||||
:columns="columns"
|
||||
:rows="transactions.data"
|
||||
row-key="name"
|
||||
:options="{
|
||||
showTooltip: false,
|
||||
selectable: false,
|
||||
onRowClick: (row: { [key: string]: any }) => {
|
||||
openForm(row)
|
||||
},
|
||||
}"
|
||||
>
|
||||
<ListHeader
|
||||
class="mb-2 grid items-center space-x-4 rounded bg-surface-gray-2 p-2"
|
||||
>
|
||||
<ListHeaderItem :item="item" v-for="item in columns">
|
||||
<template #prefix="{ item }">
|
||||
<FeatherIcon
|
||||
v-if="item.icon"
|
||||
:name="item.icon"
|
||||
class="h-4 w-4 stroke-1.5"
|
||||
/>
|
||||
</template>
|
||||
</ListHeaderItem>
|
||||
</ListHeader>
|
||||
|
||||
<ListRows>
|
||||
<ListRow :row="row" v-for="row in transactions.data">
|
||||
<template #default="{ column, item }">
|
||||
<ListRowItem :item="row[column.key]" :align="column.align">
|
||||
<FormControl
|
||||
v-if="
|
||||
['payment_received', 'payment_for_certificate'].includes(
|
||||
column.key
|
||||
)
|
||||
"
|
||||
type="checkbox"
|
||||
v-model="row[column.key]"
|
||||
:disabled="true"
|
||||
/>
|
||||
<div v-else-if="column.key == 'amount'">
|
||||
{{ getCurrencySymbol(row['currency']) }} {{ row[column.key] }}
|
||||
</div>
|
||||
<div v-else class="leading-5 text-sm">
|
||||
{{ row[column.key] }}
|
||||
</div>
|
||||
</ListRowItem>
|
||||
</template>
|
||||
</ListRow>
|
||||
</ListRows>
|
||||
</ListView>
|
||||
<div
|
||||
v-if="transactions.data.length && transactions.hasNextPage"
|
||||
class="flex justify-center mt-4"
|
||||
>
|
||||
<Button @click="transactions.next()">
|
||||
<template #prefix>
|
||||
<RefreshCw class="h-3 w-3 stroke-1.5" />
|
||||
</template>
|
||||
{{ __('Load More') }}
|
||||
</Button>
|
||||
</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,
|
||||
FeatherIcon,
|
||||
ListRows,
|
||||
ListRow,
|
||||
ListRowItem,
|
||||
FormControl,
|
||||
} 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 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',
|
||||
})
|
||||
|
||||
watch(
|
||||
[billingName, member, paymentReceived, paymentForCertificate],
|
||||
([
|
||||
newBillingName,
|
||||
newMember,
|
||||
newPaymentReceived,
|
||||
newPaymentForCertificate,
|
||||
]) => {
|
||||
transactions.update({
|
||||
filters: [
|
||||
newBillingName ? [['billing_name', 'like', `%${newBillingName}%`]] : [],
|
||||
newMember ? [['member', '=', newMember]] : [],
|
||||
newPaymentReceived
|
||||
? [['payment_received', '=', newPaymentReceived]]
|
||||
: [],
|
||||
newPaymentForCertificate
|
||||
? [['payment_for_certificate', '=', newPaymentForCertificate]]
|
||||
: [],
|
||||
].flat(),
|
||||
})
|
||||
transactions.reload()
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
const openForm = (transaction: { [key: string]: any }) => {
|
||||
currentTransaction.value = transaction
|
||||
showForm.value = true
|
||||
}
|
||||
|
||||
const getCurrencySymbol = (currency: string) => {
|
||||
const currencySymbols: Record<string, string> = {
|
||||
USD: '$',
|
||||
EUR: '€',
|
||||
GBP: '£',
|
||||
INR: '₹',
|
||||
AED: 'د.إ',
|
||||
CHF: 'Fr',
|
||||
JPY: '¥',
|
||||
AUD: '$',
|
||||
}
|
||||
return currencySymbols[currency] || currency
|
||||
}
|
||||
|
||||
const columns = computed(() => {
|
||||
return [
|
||||
{
|
||||
label: __('Billing Name'),
|
||||
icon: 'user',
|
||||
key: 'billing_name',
|
||||
width: '30%',
|
||||
},
|
||||
{
|
||||
label: __('Amount'),
|
||||
icon: 'dollar-sign',
|
||||
key: 'amount',
|
||||
width: '20%',
|
||||
align: 'right',
|
||||
},
|
||||
{
|
||||
label: __('Payment Received'),
|
||||
icon: 'check-circle',
|
||||
key: 'payment_received',
|
||||
width: '25%',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
label: __('Payment for Certificate'),
|
||||
icon: 'award',
|
||||
key: 'payment_for_certificate',
|
||||
width: '25%',
|
||||
align: 'center',
|
||||
},
|
||||
]
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user