feat: update refund ticket handling and enhance service schemas

- Removed the taskRefundTicket method from CronService to streamline scheduling logic.
- Updated PayosService to include MessageContextType for chat messages, improving message context handling.
- Enhanced RefundTicketSchema with additional fields for requester and improved error handling for unauthorized access.
- Implemented logic to update order and schedule statuses upon refund ticket approval, ensuring proper state management.
- Modified ServiceSchema to utilize createManyAndReturn for message creation, enhancing notification efficiency.

These changes improve the handling of refund tickets and enhance the overall functionality of the service schemas, ensuring better user experience and state management.
This commit is contained in:
2024-12-13 19:35:23 +07:00
parent 2eb2919965
commit 0a1b42f908
6 changed files with 85 additions and 56 deletions

View File

@@ -99,51 +99,6 @@ export class CronService {
}
}
// handle refund ticket by order, if order status is refunded, disable schedule and remove schedule date in future
@Cron(CronExpression.EVERY_MINUTE)
async taskRefundTicket() {
Logger.log('Handling refund ticket', 'CronService')
const now = DateTimeUtils.now().toJSDate()
// get all orders where status is REFUNDED and has schedule.dates in future
const orders = await this.prisma.order.findMany({
where: {
status: OrderStatus.REFUNDED,
schedule: {
dates: {
some: {
end: {
gt: now,
},
},
},
},
},
include: {
schedule: {
include: {
dates: true,
},
},
},
})
Logger.log(`Found ${orders.length} orders to handle`, 'CronService')
for (const order of orders) {
await this.prisma.schedule.update({
where: { id: order.scheduleId },
data: { status: ScheduleStatus.REFUNDED },
})
}
// remove schedule date in future
for (const order of orders) {
await this.prisma.scheduleDate.deleteMany({
where: {
id: { in: order.schedule.dates.map((d) => d.id) },
start: { gt: now },
},
})
}
}
// cron every 1 minute to check if there is any schedule date start in less than 30 minutes
@Cron(CronExpression.EVERY_MINUTE)
async taskCheckScheduleDateStart() {

View File

@@ -11,6 +11,7 @@ import type {
} from '@payos/node/lib/type'
import {
ChatRoomType,
MessageContextType,
MessageType,
OrderStatus,
PaymentStatus,
@@ -129,6 +130,7 @@ export class PayosService {
type: MessageType.TEXT,
chatRoomId: chatRoom.id,
senderId: mentorId,
context: MessageContextType.CHAT,
},
})
return {

View File

@@ -1,5 +1,14 @@
import { Inject, Injectable } from '@nestjs/common'
import { MessageContextType, MessageType, OrderStatus, PaymentStatus, RefundTicketStatus, Role } from '@prisma/client'
import {
MessageContextType,
MessageType,
OrderStatus,
PaymentStatus,
RefundTicketStatus,
Role,
ScheduleDateStatus,
ScheduleStatus,
} from '@prisma/client'
import { Pothos, PothosRef, PothosSchema, SchemaBuilderToken } from '@smatch-corp/nestjs-pothos'
import { PubSubEvent } from 'src/common/pubsub/pubsub-event'
import { DateTimeUtils } from 'src/common/utils/datetime.utils'
@@ -56,6 +65,9 @@ export class RefundTicketSchema extends PothosSchema {
order: t.relation('order', {
description: 'The order for the refund ticket.',
}),
requester: t.relation('requester', {
description: 'The requester of the refund ticket.',
}),
}),
})
}
@@ -123,7 +135,9 @@ export class RefundTicketSchema extends PothosSchema {
if (ctx.isSubscription) {
throw new Error('Subscription is not allowed')
}
if (!ctx.http.me) {
throw new Error('Unauthorized')
}
// 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')
@@ -216,6 +230,7 @@ export class RefundTicketSchema extends PothosSchema {
bankBin: bankBin,
bankAccountNumber: bankAccountNumber,
bankName: bankName,
requesterId: ctx.http.me.id,
},
})
// notify all Moderator
@@ -272,9 +287,56 @@ export class RefundTicketSchema extends PothosSchema {
data: {
status: args.action === 'APPROVE' ? RefundTicketStatus.APPROVED : RefundTicketStatus.REJECTED,
rejectedReason: args.action === 'REJECT' ? args.reason : undefined,
moderatorId: ctx.http.me?.id,
moderatorId: ctx.http.me.id,
},
include: {
order: true,
},
})
// update order status
await this.prisma.order.update({
where: { id: refundTicket.orderId },
data: {
status: OrderStatus.REFUNDED,
},
})
// change schedule status
await this.prisma.schedule.update({
where: { id: refundTicket.order.scheduleId },
data: {
status: ScheduleStatus.REFUNDED,
},
})
// change schedule date status in future
await this.prisma.scheduleDate.updateMany({
where: {
scheduleId: refundTicket.order.scheduleId,
start: {
gt: DateTimeUtils.nowAsJSDate(),
},
},
data: {
status: ScheduleDateStatus.EXPIRED,
},
})
// send notification to requester
const requester = await this.prisma.user.findUnique({
where: { id: refundTicket.requesterId },
})
if (!requester) {
throw new Error('Requester not found')
}
const message = await this.prisma.message.create({
data: {
senderId: ctx.http.me.id,
recipientId: requester.id,
type: MessageType.TEXT,
content: `Yêu cầu hoàn tiền của bạn đã được ${args.action === 'APPROVE' ? 'chấp thuận' : 'từ chối'}`,
sentAt: DateTimeUtils.nowAsJSDate(),
context: MessageContextType.NOTIFICATION,
},
})
ctx.http.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${requester.id}`, message)
return refundTicket
},
}),

View File

@@ -277,7 +277,7 @@ export class ServiceSchema extends PothosSchema {
const moderatorIds = await this.prisma.user.findMany({
where: { role: Role.MODERATOR },
})
const messages = await this.prisma.message.createMany({
const messages = await this.prisma.message.createManyAndReturn({
data: moderatorIds.map((moderator) => ({
senderId: ctx.http.me?.id ?? '',
recipientId: moderator.id,
@@ -287,8 +287,8 @@ export class ServiceSchema extends PothosSchema {
context: MessageContextType.NOTIFICATION,
})),
})
moderatorIds.forEach((moderator) => {
ctx.http.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${moderator.id}`, messages)
messages.forEach((message) => {
ctx.http.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${message.recipientId}`, message)
})
return service
},

File diff suppressed because one or more lines are too long