refactor: enhance refund ticket logic and role-based access control

- Updated the RefundTicket schema to allow both customers and center mentors to request refunds, improving flexibility in refund processing.
- Refined bank detail checks to differentiate between customers and center mentors, ensuring appropriate handling of bank information.
- Implemented special handling for center mentors to always allow full refunds, enhancing user experience.
- Improved error messages and validation checks throughout the refund process for better clarity and user guidance.
This commit is contained in:
2024-12-09 18:43:03 +07:00
parent e3a06f1ba9
commit 4ba3077a9b
2 changed files with 56 additions and 22 deletions

View File

@@ -212,7 +212,6 @@ export class QuizSchema extends PothosSchema {
'centerMentorId', 'centerMentorId',
'createdAt', 'createdAt',
'updatedAt', 'updatedAt',
'service',
]), ]),
required: true, required: true,
}), }),

View File

@@ -122,14 +122,20 @@ export class RefundTicketSchema extends PothosSchema {
if (ctx.isSubscription) { if (ctx.isSubscription) {
throw new Error('Subscription is not allowed') throw new Error('Subscription is not allowed')
} }
if (ctx.http.me?.role !== Role.CUSTOMER) {
throw new Error('Only customers can request refund') // Check if the user is a customer or a center mentor
if (ctx.http.me?.role !== Role.CUSTOMER && ctx.http.me?.role !== Role.CENTER_MENTOR) {
throw new Error('Only customers and center mentors can request refund')
} }
// check if bank bin and bank account number is exists else throw error
if (!ctx.http.me?.bankBin || !ctx.http.me?.bankAccountNumber) { // Check bank details for non-center mentors
throw new Error('Bank bin and bank account number are required, please update your profile first') if (ctx.http.me?.role !== Role.CENTER_MENTOR) {
if (!ctx.http.me?.bankBin || !ctx.http.me?.bankAccountNumber) {
throw new Error('Bank bin and bank account number are required, please update your profile first')
}
} }
// check if order exists
// Check if order exists
const order = await this.prisma.order.findUnique({ const order = await this.prisma.order.findUnique({
where: { id: args.orderId }, where: { id: args.orderId },
include: { include: {
@@ -139,49 +145,78 @@ export class RefundTicketSchema extends PothosSchema {
if (!order) { if (!order) {
throw new Error('Order not found') throw new Error('Order not found')
} }
// check if order status is PAID
// Check if order status is PAID
if (order.status !== OrderStatus.PAID) { if (order.status !== OrderStatus.PAID) {
throw new Error('Order is not paid') throw new Error('Order is not paid')
} }
// check if order total is not null
// Check if order total is not null
if (!order.total || order.total === 0) { if (!order.total || order.total === 0) {
throw new Error('Order total is null or free') throw new Error('Order total is null or free')
} }
if (order.refundTicket) { if (order.refundTicket) {
throw new Error('Refund ticket already exists') throw new Error('Refund ticket already exists')
} }
// calculate refund amount based on order time: if order is less than 24 hours, refund 100%, if more than 24 hours, less than 48 hours, refund 50%, if more than 72 hours, cannot refund
// Calculate refund amount based on order time
const now = DateTimeUtils.now() const now = DateTimeUtils.now()
const orderDate = DateTimeUtils.fromDate(order.createdAt) const orderDate = DateTimeUtils.fromDate(order.createdAt)
const diffTime = Math.abs(now.diff(orderDate).toMillis()) const diffTime = Math.abs(now.diff(orderDate).toMillis())
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24))
let refundAmount = 0 let refundAmount = 0
if (diffDays < 1) {
// Special handling for center mentors - full refund always allowed
if (ctx.http.me?.role === Role.CENTER_MENTOR) {
refundAmount = order.total refundAmount = order.total
} else if (diffDays < 3) { } else {
refundAmount = order.total * 0.5 // Existing refund logic for customers
if (diffDays < 1) {
refundAmount = order.total
} else if (diffDays < 3) {
refundAmount = order.total * 0.5
}
} }
if (refundAmount === 0) { if (refundAmount === 0) {
throw new Error('Cannot refund after 3 days') throw new Error('Cannot refund after 3 days')
} }
// create refund ticket
// get bank name from bank bin from banks.json // Prepare bank details
// biome-ignore lint/suspicious/noExplicitAny: <explanation> let bankBin = ctx.http.me?.bankBin
const bank = banks.data.find((bank: any) => bank.bin === ctx.http.me?.bankBin) let bankAccountNumber = ctx.http.me?.bankAccountNumber
if (!bank) { let bankName = ''
throw new Error('Bank not found')
// For center mentors, use a default or system bank account
if (ctx.http.me?.role === Role.CENTER_MENTOR) {
// You might want to replace this with a specific system bank account
bankBin = 'SYSTEM_MENTOR_REFUND'
bankAccountNumber = 'SYSTEM_MENTOR_ACCOUNT'
bankName = 'Center Mentor Refund Account'
} else {
// Existing bank lookup for customers
const bank = banks.data.find((bank: any) => bank.bin === bankBin)
if (!bank) {
throw new Error('Bank not found')
}
bankName = bank.name
} }
// Create refund ticket
const refundTicket = await this.prisma.refundTicket.create({ const refundTicket = await this.prisma.refundTicket.create({
data: { data: {
orderId: order.id, orderId: order.id,
status: RefundTicketStatus.PENDING, status: RefundTicketStatus.PENDING,
amount: refundAmount, amount: refundAmount,
reason: args.reason, reason: args.reason,
bankBin: ctx.http.me?.bankBin, bankBin: bankBin,
bankAccountNumber: ctx.http.me?.bankAccountNumber, bankAccountNumber: bankAccountNumber,
bankName: bank.name, bankName: bankName,
}, },
}) })
return refundTicket return refundTicket
}, },
}), }),