165 lines
4.9 KiB
TypeScript
165 lines
4.9 KiB
TypeScript
import { Inject, Injectable, Logger } from '@nestjs/common'
|
|
|
|
import { PrismaService } from '../Prisma/prisma.service'
|
|
import PayOS from '@payos/node'
|
|
import type {
|
|
CheckoutRequestType,
|
|
CheckoutResponseDataType,
|
|
WebhookType,
|
|
WebhookDataType,
|
|
CancelPaymentLinkRequestType,
|
|
DataType,
|
|
} from '@payos/node/lib/type'
|
|
import {
|
|
ChatRoomType,
|
|
MessageType,
|
|
OrderStatus,
|
|
PaymentStatus,
|
|
ScheduleDateStatus,
|
|
ScheduleStatus,
|
|
} from '@prisma/client'
|
|
export type CreatePaymentBody = CheckoutRequestType
|
|
export type CreatePaymentResponse = CheckoutResponseDataType
|
|
@Injectable()
|
|
export class PayosService {
|
|
constructor(
|
|
private readonly prisma: PrismaService,
|
|
@Inject('PayOS') private readonly payos: PayOS,
|
|
) {}
|
|
|
|
async ping() {
|
|
return 'pong'
|
|
}
|
|
|
|
async webhook(data: WebhookType) {
|
|
Logger.log(`Webhook received: ${JSON.stringify(data)}`)
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/* Test payment */
|
|
/* -------------------------------------------------------------------------- */
|
|
if (data.data.orderCode === 123) {
|
|
return {
|
|
message: 'Payment received',
|
|
}
|
|
}
|
|
const paymentData = this.payos.verifyPaymentWebhookData(data)
|
|
if (!paymentData) {
|
|
Logger.error(`Invalid checksum: ${JSON.stringify(data)}`)
|
|
throw new Error('Invalid checksum')
|
|
}
|
|
const paymentStatus =
|
|
paymentData.code === '00' ? PaymentStatus.PAID : PaymentStatus.CANCELLED
|
|
/* ---------------------------- begin transaction --------------------------- */
|
|
try {
|
|
await this.prisma.$transaction(async (tx) => {
|
|
// update payment status
|
|
const payment = await tx.payment.update({
|
|
where: { paymentCode: paymentData.paymentLinkId },
|
|
data: {
|
|
status: paymentStatus,
|
|
},
|
|
})
|
|
const orderStatus =
|
|
paymentStatus === PaymentStatus.PAID
|
|
? OrderStatus.PAID
|
|
: OrderStatus.FAILED
|
|
// update order status
|
|
await tx.order.update({
|
|
where: { id: payment.orderId },
|
|
data: {
|
|
status: orderStatus,
|
|
},
|
|
})
|
|
const order = await tx.order.findUniqueOrThrow({
|
|
where: { id: payment.orderId },
|
|
})
|
|
const schedule = await tx.schedule.findUnique({
|
|
where: { id: order?.scheduleId },
|
|
})
|
|
// update schedule order id
|
|
await tx.schedule.update({
|
|
where: { id: schedule?.id },
|
|
data: {
|
|
customerId: order?.userId,
|
|
orderId: order?.id,
|
|
status: ScheduleStatus.IN_PROGRESS,
|
|
},
|
|
})
|
|
// get mentor id from managed service
|
|
const managedService = await tx.managedService.findUniqueOrThrow({
|
|
where: { id: schedule?.managedServiceId },
|
|
})
|
|
const mentorId = managedService.mentorId
|
|
// get center id from order service
|
|
const orderService = await tx.service.findUniqueOrThrow({
|
|
where: { id: order?.serviceId },
|
|
})
|
|
const centerId = orderService.centerId
|
|
// create chatroom for support
|
|
const chatRoom = await tx.chatRoom.create({
|
|
data: {
|
|
type: ChatRoomType.SUPPORT,
|
|
customerId: order.userId,
|
|
centerId: centerId,
|
|
mentorId: mentorId,
|
|
},
|
|
})
|
|
// update order chatRoomId
|
|
await tx.order.update({
|
|
where: { id: order.id },
|
|
data: {
|
|
chatRoomId: chatRoom.id,
|
|
},
|
|
})
|
|
// update orderId for schedule dates
|
|
await tx.scheduleDate.updateMany({
|
|
where: { scheduleId: schedule?.id },
|
|
data: {
|
|
orderId: order.id,
|
|
},
|
|
})
|
|
// send first message from mentor to customer
|
|
await tx.message.create({
|
|
data: {
|
|
content:
|
|
'Xin chào, mình là hướng dẫn viên của bạn, hãy bắt đầu học ngay nhé!',
|
|
type: MessageType.TEXT,
|
|
chatRoomId: chatRoom.id,
|
|
senderId: mentorId,
|
|
},
|
|
})
|
|
return {
|
|
message: 'Payment received',
|
|
}
|
|
})
|
|
} catch (error) {
|
|
Logger.error(`Transaction failed: ${error}`)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
async createPaymentURL(body: CheckoutRequestType) {
|
|
return await this.payos.createPaymentLink(body)
|
|
}
|
|
|
|
async createPayment(body: CreatePaymentBody): Promise<CreatePaymentResponse> {
|
|
return await this.payos.createPaymentLink(body)
|
|
}
|
|
|
|
async getPaymentStatus(orderId: string | number) {
|
|
return await this.payos.getPaymentLinkInformation(orderId)
|
|
}
|
|
|
|
async cancelPaymentURL(
|
|
orderId: string | number,
|
|
cancellationReason?: string,
|
|
) {
|
|
return await this.payos.cancelPaymentLink(orderId, cancellationReason)
|
|
}
|
|
|
|
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
async refundPayment(body: any) {
|
|
return body
|
|
}
|
|
}
|