Skip to content

Commit b079409

Browse files
committed
feat: billing page
1 parent 1f18ef4 commit b079409

File tree

4 files changed

+228
-0
lines changed

4 files changed

+228
-0
lines changed

frontend/src/pages/Billing.vue

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
<template>
2+
<div class="text-base h-screen">
3+
<div v-if="access.data?.access" class="mt-20 w-1/2 mx-auto">
4+
<div class="text-3xl font-bold">
5+
{{ __('Billing Details') }}
6+
</div>
7+
<div class="text-gray-600 mt-1">
8+
{{ __('Enter the billing information to complete the payment.') }}
9+
</div>
10+
<div class="border rounded-md p-8 mt-10">
11+
<div class="text-xl font-semibold">
12+
{{ __('Address') }}
13+
</div>
14+
<div class="text-gray-600 mt-1">
15+
{{ __('Specify your billing address correctly.') }}
16+
</div>
17+
<div class="grid grid-cols-2 gap-5 mt-4">
18+
<div>
19+
<div class="mt-4">
20+
<div class="mb-1.5 text-sm text-gray-700">
21+
{{ __('Billing Name') }}
22+
</div>
23+
<Input type="text" v-model="billingDetails.billing_name" />
24+
</div>
25+
<div class="mt-4">
26+
<div class="mb-1.5 text-sm text-gray-700">
27+
{{ __('Address Line 1') }}
28+
</div>
29+
<Input type="text" v-model="billingDetails.address_line_1" />
30+
</div>
31+
<div class="mt-4">
32+
<div class="mb-1.5 text-sm text-gray-700">
33+
{{ __('Address Line 2') }}
34+
</div>
35+
<Input type="text" v-model="billingDetails.address_line_2" />
36+
</div>
37+
<div class="mt-4">
38+
<div class="mb-1.5 text-sm text-gray-700">
39+
{{ __('City') }}
40+
</div>
41+
<Input type="text" v-model="billingDetails.city" />
42+
</div>
43+
<div class="mt-4">
44+
<div class="mb-1.5 text-sm text-gray-700">
45+
{{ __('State') }}
46+
</div>
47+
<Input type="text" v-model="billingDetails.state" />
48+
</div>
49+
</div>
50+
<div>
51+
<div class="mt-4">
52+
<div class="mb-1.5 text-sm text-gray-700">
53+
{{ __('Country') }}
54+
</div>
55+
<Input type="text" v-model="billingDetails.country" />
56+
</div>
57+
<div class="mt-4">
58+
<div class="mb-1.5 text-sm text-gray-700">
59+
{{ __('Postal Code') }}
60+
</div>
61+
<Input type="text" v-model="billingDetails.pincode" />
62+
</div>
63+
<div class="mt-4">
64+
<div class="mb-1.5 text-sm text-gray-700">
65+
{{ __('Phone Number') }}
66+
</div>
67+
<Input type="text" v-model="billingDetails.phone" />
68+
</div>
69+
<div class="mt-4">
70+
<div class="mb-1.5 text-sm text-gray-700">
71+
{{ __('Source') }}
72+
</div>
73+
<Input type="text" v-model="billingDetails.source" />
74+
</div>
75+
<div v-if="billingDetails.country == 'India'" class="mt-4">
76+
<div class="mb-1.5 text-sm text-gray-700">
77+
{{ __('GST Number') }}
78+
</div>
79+
<Input type="text" v-model="billingDetails.gstin" />
80+
</div>
81+
<div v-if="billingDetails.country == 'India'" class="mt-4">
82+
<div class="mb-1.5 text-sm text-gray-700">
83+
{{ __('Pan Number') }}
84+
</div>
85+
<Input type="text" v-model="billingDetails.pan" />
86+
</div>
87+
</div>
88+
</div>
89+
<Button variant="solid" class="mt-8">
90+
{{ __('Proceed to Payment') }}
91+
</Button>
92+
</div>
93+
</div>
94+
<div v-else>
95+
<div class="text-base border rounded-md w-1/3 mx-auto my-32">
96+
<div class="border-b px-5 py-3 font-medium">
97+
<span
98+
class="inline-flex items-center before:bg-red-600 before:w-2 before:h-2 before:rounded-md before:mr-2"
99+
></span>
100+
{{ __('Not Permitted') }}
101+
</div>
102+
<div class="px-5 py-3">
103+
<div class="mb-4 leading-6">
104+
{{ access.data?.message }}
105+
</div>
106+
<Button
107+
v-if="!user.data.name"
108+
variant="solid"
109+
class="w-full"
110+
@click="redirectToLogin()"
111+
>
112+
{{ __('Login') }}
113+
</Button>
114+
<router-link
115+
v-else-if="type == 'course'"
116+
:to="{
117+
name: 'Courses',
118+
}"
119+
>
120+
<Button variant="solid">
121+
{{ __('Checkout Courses') }}
122+
</Button>
123+
</router-link>
124+
<router-link
125+
v-else-if="type == 'batch'"
126+
:to="{
127+
name: 'Batches',
128+
}"
129+
>
130+
<Button varian="solid">
131+
{{ __('Checkout Batches') }}
132+
</Button>
133+
</router-link>
134+
</div>
135+
</div>
136+
</div>
137+
</div>
138+
</template>
139+
<script setup>
140+
import { Input, Button, createResource } from 'frappe-ui'
141+
import { reactive, inject, onMounted, ref } from 'vue'
142+
143+
const user = inject('$user')
144+
145+
const props = defineProps({
146+
type: {
147+
type: String,
148+
required: true,
149+
},
150+
name: {
151+
type: String,
152+
required: true,
153+
},
154+
})
155+
156+
const access = createResource({
157+
url: 'lms.lms.api.validate_billing_access',
158+
params: {
159+
type: props.type,
160+
name: props.name,
161+
},
162+
auto: true,
163+
})
164+
165+
const billingDetails = reactive({
166+
billing_name: '',
167+
address_line_1: '',
168+
address_line_2: '',
169+
city: '',
170+
state: '',
171+
pincode: '',
172+
country: '',
173+
phone: '',
174+
source: '',
175+
gstin: '',
176+
pan: '',
177+
})
178+
179+
const redirectToLogin = () => {
180+
window.location.href = `/login?redirect-to=/billing/${props.type}/${props.name}`
181+
}
182+
</script>

frontend/src/router.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ const routes = [
4343
component: () => import('@/pages/Batch.vue'),
4444
props: true,
4545
},
46+
{
47+
path: '/billing/:type/:name',
48+
name: 'Billing',
49+
component: () => import('@/pages/Billing.vue'),
50+
props: true,
51+
},
4652
{
4753
path: '/statistics',
4854
name: 'Statistics',

lms/lms/api.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import frappe
55
from frappe.translate import get_all_translations
6+
from frappe import _
67

78

89
@frappe.whitelist()
@@ -163,3 +164,39 @@ def get_translations():
163164
else:
164165
language = frappe.db.get_single_value("System Settings", "language")
165166
return get_all_translations(language)
167+
168+
169+
@frappe.whitelist()
170+
def validate_billing_access(type, name):
171+
access = True
172+
message = ""
173+
174+
if frappe.session.user == "Guest":
175+
access = False
176+
message = _("Please login to continue with payment.")
177+
178+
if type not in ["course", "batch"]:
179+
access = False
180+
message = _("Module is incorrect.")
181+
182+
if not frappe.db.exists(type, name):
183+
access = False
184+
message = _("Module Name is incorrect or does not exist.")
185+
186+
if type == "course":
187+
membership = frappe.db.exists(
188+
"LMS Enrollment", {"member": frappe.session.user, "course": name}
189+
)
190+
if membership:
191+
access = False
192+
message = _("You are already enrolled for this course.")
193+
194+
else:
195+
membership = frappe.db.exists(
196+
"Batch Student", {"student": frappe.session.user, "parent": name}
197+
)
198+
if membership:
199+
access = False
200+
message = _("You are already enrolled for this batch.")
201+
202+
return {"access": access, "message": message}

lms/lms/utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,9 @@ def get_course_details(course):
11921192
"published",
11931193
"upcoming",
11941194
"status",
1195+
"paid_course",
1196+
"course_price",
1197+
"currency",
11951198
],
11961199
as_dict=1,
11971200
)

0 commit comments

Comments
 (0)