Refactor ClerkService and OrderSchema for improved type safety; update RefundTicketSchema to include new refund request and processing mutations. Clean up import statements and enhance descriptions for better clarity. Update subproject commit reference in epess-database.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { Injectable, Logger } from '@nestjs/common'
|
import { Injectable, Logger } from '@nestjs/common'
|
||||||
|
|
||||||
import { PrismaService } from '../Prisma/prisma.service'
|
import { PrismaService } from '../Prisma/prisma.service'
|
||||||
import { clerkClient } from '@clerk/express'
|
import { clerkClient, WebhookEventType } from '@clerk/express'
|
||||||
|
|
||||||
export interface ClerkResponse {}
|
export interface ClerkResponse {}
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -15,7 +15,7 @@ export class ClerkService {
|
|||||||
return { message: `Webhook received: ${eventType}` }
|
return { message: `Webhook received: ${eventType}` }
|
||||||
}
|
}
|
||||||
// dispatch the event
|
// dispatch the event
|
||||||
dispatchEvent(eventType: string, data: any) {
|
dispatchEvent(eventType: WebhookEventType, data: any) {
|
||||||
// event types:
|
// event types:
|
||||||
// user.created
|
// user.created
|
||||||
// user.updated
|
// user.updated
|
||||||
@@ -56,9 +56,7 @@ export class ClerkService {
|
|||||||
async eventUserCreated(data: any) {
|
async eventUserCreated(data: any) {
|
||||||
const primary_email_address_id = data.primary_email_address_id
|
const primary_email_address_id = data.primary_email_address_id
|
||||||
// get primary email address on email_addresses by querying email_addresses with primary_email_address_id
|
// get primary email address on email_addresses by querying email_addresses with primary_email_address_id
|
||||||
let primary_email_address = data.email_addresses.find(
|
let primary_email_address = data.email_addresses.find((email: any) => email.id === primary_email_address_id)
|
||||||
(email: any) => email.id === primary_email_address_id,
|
|
||||||
)
|
|
||||||
console.log(primary_email_address)
|
console.log(primary_email_address)
|
||||||
if (!primary_email_address) {
|
if (!primary_email_address) {
|
||||||
primary_email_address = ''
|
primary_email_address = ''
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common'
|
import { Inject, Injectable } from '@nestjs/common'
|
||||||
import {
|
import { Pothos, PothosRef, PothosSchema, SchemaBuilderToken } from '@smatch-corp/nestjs-pothos'
|
||||||
Pothos,
|
|
||||||
PothosRef,
|
|
||||||
PothosSchema,
|
|
||||||
SchemaBuilderToken,
|
|
||||||
} from '@smatch-corp/nestjs-pothos'
|
|
||||||
import { Builder } from '../Graphql/graphql.builder'
|
import { Builder } from '../Graphql/graphql.builder'
|
||||||
import { PrismaService } from '../Prisma/prisma.service'
|
import { PrismaService } from '../Prisma/prisma.service'
|
||||||
import { OrderStatus } from '@prisma/client'
|
import { OrderStatus } from '@prisma/client'
|
||||||
@@ -90,8 +85,7 @@ export class OrderSchema extends PothosSchema {
|
|||||||
this.builder.queryFields((t) => ({
|
this.builder.queryFields((t) => ({
|
||||||
orders: t.prismaField({
|
orders: t.prismaField({
|
||||||
type: [this.order()],
|
type: [this.order()],
|
||||||
description:
|
description: 'Retrieve a list of orders with optional filtering, ordering, and pagination.',
|
||||||
'Retrieve a list of orders with optional filtering, ordering, and pagination.',
|
|
||||||
args: this.builder.generator.findManyArgs('Order'),
|
args: this.builder.generator.findManyArgs('Order'),
|
||||||
resolve: async (query, _root, args, _ctx, _info) => {
|
resolve: async (query, _root, args, _ctx, _info) => {
|
||||||
return await this.prisma.order.findMany({
|
return await this.prisma.order.findMany({
|
||||||
@@ -160,10 +154,7 @@ export class OrderSchema extends PothosSchema {
|
|||||||
const order = await this.prisma.order.findUnique({
|
const order = await this.prisma.order.findUnique({
|
||||||
where: { id: schedule.orderId },
|
where: { id: schedule.orderId },
|
||||||
})
|
})
|
||||||
if (
|
if (order?.status === OrderStatus.PAID || order?.status === OrderStatus.PENDING) {
|
||||||
order?.status === OrderStatus.PAID ||
|
|
||||||
order?.status === OrderStatus.PENDING
|
|
||||||
) {
|
|
||||||
throw new Error('Schedule already has an order')
|
throw new Error('Schedule already has an order')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,17 +204,9 @@ export class OrderSchema extends PothosSchema {
|
|||||||
description: service.name,
|
description: service.name,
|
||||||
buyerName: ctx.http.me?.name ?? '',
|
buyerName: ctx.http.me?.name ?? '',
|
||||||
buyerEmail: ctx.http.me?.email ?? '',
|
buyerEmail: ctx.http.me?.email ?? '',
|
||||||
returnUrl: `${process.env.PAYOS_RETURN_URL}`.replace(
|
returnUrl: `${process.env.PAYOS_RETURN_URL}`.replace('<serviceId>', service.id),
|
||||||
'<serviceId>',
|
cancelUrl: `${process.env.PAYOS_RETURN_URL}`.replace('<serviceId>', service.id),
|
||||||
service.id,
|
expiredAt: DateTimeUtils.now().plus({ minutes: 15 }).toUnixInteger(),
|
||||||
),
|
|
||||||
cancelUrl: `${process.env.PAYOS_RETURN_URL}`.replace(
|
|
||||||
'<serviceId>',
|
|
||||||
service.id,
|
|
||||||
),
|
|
||||||
expiredAt: DateTimeUtils.now()
|
|
||||||
.plus({ minutes: 15 })
|
|
||||||
.toUnixInteger(),
|
|
||||||
})
|
})
|
||||||
// update order payment id
|
// update order payment id
|
||||||
await this.prisma.order.update({
|
await this.prisma.order.update({
|
||||||
@@ -269,10 +252,7 @@ export class OrderSchema extends PothosSchema {
|
|||||||
description: 'Update an existing order.',
|
description: 'Update an existing order.',
|
||||||
args: {
|
args: {
|
||||||
data: t.arg({
|
data: t.arg({
|
||||||
type: this.builder.generator.getUpdateInput('Order', [
|
type: this.builder.generator.getUpdateInput('Order', ['status', 'total']),
|
||||||
'status',
|
|
||||||
'total',
|
|
||||||
]),
|
|
||||||
required: true,
|
required: true,
|
||||||
}),
|
}),
|
||||||
where: t.arg({
|
where: t.arg({
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common'
|
import { Inject, Injectable } from '@nestjs/common'
|
||||||
import {
|
import { Pothos, PothosRef, PothosSchema, SchemaBuilderToken } from '@smatch-corp/nestjs-pothos'
|
||||||
Pothos,
|
|
||||||
PothosRef,
|
|
||||||
PothosSchema,
|
|
||||||
SchemaBuilderToken,
|
|
||||||
} from '@smatch-corp/nestjs-pothos'
|
|
||||||
import { Builder } from '../Graphql/graphql.builder'
|
import { Builder } from '../Graphql/graphql.builder'
|
||||||
import { PrismaService } from '../Prisma/prisma.service'
|
import { PrismaService } from '../Prisma/prisma.service'
|
||||||
import { PaymentStatus } from '@prisma/client'
|
import { OrderStatus, PaymentStatus, RefundTicketStatus, Role } from '@prisma/client'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RefundTicketSchema extends PothosSchema {
|
export class RefundTicketSchema extends PothosSchema {
|
||||||
@@ -30,7 +25,7 @@ export class RefundTicketSchema extends PothosSchema {
|
|||||||
description: 'The amount of the refund ticket.',
|
description: 'The amount of the refund ticket.',
|
||||||
}),
|
}),
|
||||||
status: t.expose('status', {
|
status: t.expose('status', {
|
||||||
type: PaymentStatus,
|
type: RefundTicketStatus,
|
||||||
description: 'The status of the refund ticket.',
|
description: 'The status of the refund ticket.',
|
||||||
}),
|
}),
|
||||||
createdAt: t.expose('createdAt', {
|
createdAt: t.expose('createdAt', {
|
||||||
@@ -48,14 +43,21 @@ export class RefundTicketSchema extends PothosSchema {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PothosRef()
|
||||||
|
refundTicketAction() {
|
||||||
|
return this.builder.enumType('RefundTicketAction', {
|
||||||
|
description: 'The action to take on a refund ticket.',
|
||||||
|
values: ['APPROVE', 'REJECT'],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Queries section
|
// Queries section
|
||||||
@Pothos()
|
@Pothos()
|
||||||
init(): void {
|
init(): void {
|
||||||
this.builder.queryFields((t) => ({
|
this.builder.queryFields((t) => ({
|
||||||
refundTickets: t.prismaField({
|
refundTickets: t.prismaField({
|
||||||
type: [this.refundTicket()],
|
type: [this.refundTicket()],
|
||||||
description:
|
description: 'Retrieve a list of refund tickets with optional filtering, ordering, and pagination.',
|
||||||
'Retrieve a list of refund tickets with optional filtering, ordering, and pagination.',
|
|
||||||
args: this.builder.generator.findManyArgs('RefundTicket'),
|
args: this.builder.generator.findManyArgs('RefundTicket'),
|
||||||
resolve: async (query, _root, args, _ctx, _info) => {
|
resolve: async (query, _root, args, _ctx, _info) => {
|
||||||
return await this.prisma.refundTicket.findMany({
|
return await this.prisma.refundTicket.findMany({
|
||||||
@@ -69,5 +71,81 @@ export class RefundTicketSchema extends PothosSchema {
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
|
this.builder.mutationFields((t) => ({
|
||||||
|
requestRefund: t.prismaField({
|
||||||
|
type: this.refundTicket(),
|
||||||
|
description: 'Request a refund for an order.',
|
||||||
|
args: {
|
||||||
|
orderId: t.arg({
|
||||||
|
type: 'String',
|
||||||
|
required: true,
|
||||||
|
}),
|
||||||
|
reason: t.arg({
|
||||||
|
type: 'String',
|
||||||
|
required: true,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
resolve: async (_query, _root, args, ctx, _info) => {
|
||||||
|
if (ctx.isSubscription) {
|
||||||
|
throw new Error('Subscription is not allowed')
|
||||||
|
}
|
||||||
|
if (ctx.http.me?.role !== Role.CUSTOMER) {
|
||||||
|
throw new Error('Only customers can request refund')
|
||||||
|
}
|
||||||
|
// check if order exists
|
||||||
|
const order = await this.prisma.order.findUnique({
|
||||||
|
where: { id: args.orderId },
|
||||||
|
})
|
||||||
|
if (!order) {
|
||||||
|
throw new Error('Order not found')
|
||||||
|
}
|
||||||
|
// check if order status is PAID
|
||||||
|
if (order.status !== OrderStatus.PAID) {
|
||||||
|
throw new Error('Order is not paid')
|
||||||
|
}
|
||||||
|
// check if order total is not null
|
||||||
|
if (!order.total || order.total === 0) {
|
||||||
|
throw new Error('Order total is null or free')
|
||||||
|
}
|
||||||
|
// create refund ticket
|
||||||
|
const refundTicket = await this.prisma.refundTicket.create({
|
||||||
|
data: {
|
||||||
|
orderId: order.id,
|
||||||
|
status: RefundTicketStatus.PENDING,
|
||||||
|
amount: order.total,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return refundTicket
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
processRefundTicket: t.prismaField({
|
||||||
|
type: this.refundTicket(),
|
||||||
|
description: 'Process a refund ticket, can only done by moderator',
|
||||||
|
args: {
|
||||||
|
refundTicketId: t.arg({
|
||||||
|
type: 'String',
|
||||||
|
required: true,
|
||||||
|
}),
|
||||||
|
action: t.arg({
|
||||||
|
type: this.refundTicketAction(),
|
||||||
|
required: true,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
resolve: async (_query, _root, args, ctx, _info) => {
|
||||||
|
if (ctx.isSubscription) {
|
||||||
|
throw new Error('Subscription is not allowed')
|
||||||
|
}
|
||||||
|
if (ctx.http.me?.role !== Role.MODERATOR) {
|
||||||
|
throw new Error('Only moderators can process refund tickets')
|
||||||
|
}
|
||||||
|
// update refund ticket status
|
||||||
|
const refundTicket = await this.prisma.refundTicket.update({
|
||||||
|
where: { id: args.refundTicketId },
|
||||||
|
data: { status: args.action === 'APPROVE' ? RefundTicketStatus.APPROVED : RefundTicketStatus.REJECTED },
|
||||||
|
})
|
||||||
|
return refundTicket
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user